<commit_before>package activitypub

type (
	// OutboxStream contains activities the user has published,
	// subject to the ability of the requestor to retrieve the activity (that is,
	// the contents of the outbox are filtered by the permissions of the person reading it).
	OutboxStream Outbox

	// Outbox is a type alias for an Ordered Collection
	Outbox OrderedCollection
)

// OutboxNew initializes a new Outbox
func OutboxNew() *Outbox {
	id := ObjectID("outbox")

	i := Outbox{ID: id, Type: OrderedCollectionType}
	i.Name = NaturalLanguageValueNew()
	i.Content = NaturalLanguageValueNew()
	i.Summary = NaturalLanguageValueNew()

	i.TotalItems = 0

	return &i
}

// Append adds an element to an OutboxStream
func (o *OutboxStream) Append(ob Item) error {
	o.OrderedItems = append(o.OrderedItems, ob)
	o.TotalItems++
	return nil
}

// Append adds an element to an Outbox
func (o *Outbox) Append(ob Item) error {
	o.OrderedItems = append(o.OrderedItems, ob)
	o.TotalItems++
	return nil
}

// GetID returns the ObjectID corresponding to the OutboxStream
func (o OutboxStream) GetID() *ObjectID {
	return o.Collection().GetID()
}

// GetType returns the OutboxStream's type
func (o OutboxStream) GetType() ActivityVocabularyType {
	return o.Type
}

// IsLink returns false for an OutboxStream object
func (o OutboxStream) IsLink() bool {
	return false
}

// IsObject returns true for a OutboxStream object
func (o OutboxStream) IsObject() bool {
	return true
}

// GetID returns the ObjectID corresponding to Outbox
func (o Outbox) GetID() *ObjectID {
	return o.Collection().GetID()
}

// GetType returns the Outbox's type
func (o Outbox) GetType() ActivityVocabularyType {
	return o.Type
}

// IsLink returns false for an Outbox object
func (o Outbox) IsLink() bool {
	return false
}

// IsObject returns true for a Outbox object
func (o Outbox) IsObject() bool {
	return true
}

// UnmarshalJSON
func (o *OutboxStream) UnmarshalJSON(data []byte) error {
	c := OrderedCollection(*o)
	err := c.UnmarshalJSON(data)

	*o = OutboxStream(c)

	return err
}

// UnmarshalJSON
func (o *Outbox) UnmarshalJSON(data []byte) error {
	c := OrderedCollection(*o)
	err := c.UnmarshalJSON(data)

	*o = Outbox(c)

	return err
}

// Collection returns the underlying Collection type
func (o *Outbox) Collection() CollectionInterface {
	c := OrderedCollection(*o)
	return &c
}

// Collection returns the underlying Collection type
func (o *OutboxStream) Collection() CollectionInterface {
	c := OrderedCollection(*o)
	return &c
}
<commit_msg>Removed pointer receivers for Outbox::Collection() method<commit_after>package activitypub

type (
	// OutboxStream contains activities the user has published,
	// subject to the ability of the requestor to retrieve the activity (that is,
	// the contents of the outbox are filtered by the permissions of the person reading it).
	OutboxStream Outbox

	// Outbox is a type alias for an Ordered Collection
	Outbox OrderedCollection
)

// OutboxNew initializes a new Outbox
func OutboxNew() *Outbox {
	id := ObjectID("outbox")

	i := Outbox{ID: id, Type: OrderedCollectionType}
	i.Name = NaturalLanguageValueNew()
	i.Content = NaturalLanguageValueNew()
	i.Summary = NaturalLanguageValueNew()

	i.TotalItems = 0

	return &i
}

// Append adds an element to an OutboxStream
func (o *OutboxStream) Append(ob Item) error {
	o.OrderedItems = append(o.OrderedItems, ob)
	o.TotalItems++
	return nil
}

// Append adds an element to an Outbox
func (o *Outbox) Append(ob Item) error {
	o.OrderedItems = append(o.OrderedItems, ob)
	o.TotalItems++
	return nil
}

// GetID returns the ObjectID corresponding to the OutboxStream
func (o OutboxStream) GetID() *ObjectID {
	return o.Collection().GetID()
}

// GetType returns the OutboxStream's type
func (o OutboxStream) GetType() ActivityVocabularyType {
	return o.Type
}

// IsLink returns false for an OutboxStream object
func (o OutboxStream) IsLink() bool {
	return false
}

// IsObject returns true for a OutboxStream object
func (o OutboxStream) IsObject() bool {
	return true
}

// GetID returns the ObjectID corresponding to Outbox
func (o Outbox) GetID() *ObjectID {
	return o.Collection().GetID()
}

// GetType returns the Outbox's type
func (o Outbox) GetType() ActivityVocabularyType {
	return o.Type
}

// IsLink returns false for an Outbox object
func (o Outbox) IsLink() bool {
	return false
}

// IsObject returns true for a Outbox object
func (o Outbox) IsObject() bool {
	return true
}

// UnmarshalJSON
func (o *OutboxStream) UnmarshalJSON(data []byte) error {
	c := OrderedCollection(*o)
	err := c.UnmarshalJSON(data)

	*o = OutboxStream(c)

	return err
}

// UnmarshalJSON
func (o *Outbox) UnmarshalJSON(data []byte) error {
	c := OrderedCollection(*o)
	err := c.UnmarshalJSON(data)

	*o = Outbox(c)

	return err
}

// Collection returns the underlying Collection type
func (o Outbox) Collection() CollectionInterface {
	c := OrderedCollection(o)
	return &c
}

// Collection returns the underlying Collection type
func (o OutboxStream) Collection() CollectionInterface {
	c := OrderedCollection(o)
	return &c
}
<|endoftext|>


<commit_before>package prototest

import (
	"io"

	"github.com/ghthor/filu"
	"github.com/ghthor/filu/actor"
	"github.com/ghthor/filu/auth"
	"github.com/ghthor/filu/net"
	"github.com/ghthor/filu/net/client"

	"github.com/ghthor/gospec"
	. "github.com/ghthor/gospec"
)

type mockConn struct {
	pr [2]*io.PipeReader
	pw [2]*io.PipeWriter

	server, client net.Conn
}

type readWriter struct {
	io.Reader
	io.Writer
}

func newMockConn() mockConn {
	c := mockConn{}
	c.pr[0], c.pw[0] = io.Pipe()
	c.pr[1], c.pw[1] = io.Pipe()

	c.server = net.NewGobConn(readWriter{c.pr[0], c.pw[1]})
	c.client = net.NewGobConn(readWriter{c.pr[1], c.pw[0]})

	return c
}

func (c mockConn) close() {
	for _, r := range c.pr {
		r.Close()
	}

	for _, w := range c.pw {
		w.Close()
	}
}

type mockActorDB struct {
	Get    chan<- actor.GetActorsRequest
	Select chan<- actor.SelectionRequest
}

func (db mockActorDB) close() {
	close(db.Get)
	close(db.Select)
}

func newMockActorDB(actors map[string][]string) *mockActorDB {
	getCh := make(chan actor.GetActorsRequest)
	selCh := make(chan actor.SelectionRequest)
	db := &mockActorDB{
		Get:    getCh,
		Select: selCh,
	}

	getProc := actor.NewGetActorsRequestProcessor()

	actor.SelectionRequestSource(selCh).
		WriteToProcessor(actor.NewSelectionProcessor()).
		WriteTo(getProc).
		End()

	actor.GetActorsRequestSource(getCh).
		WriteToProcessor(getProc).
		End()

	for username, names := range actors {
		for _, name := range names {
			db.createActor(username, name)
		}
	}

	return db
}

func (db mockActorDB) createActor(username, actorname string) actor.CreatedActor {
	r := actor.NewSelectionRequest(filu.Actor{
		Username: username,
		Name:     actorname,
	})
	db.Select <- r
	return <-r.CreatedActor
}

type loginTripResult struct {
	err          error
	failure      net.UserLoginFailure
	loggedInUser client.LoggedInUser
	createdUser  client.CreatedUser
}

func NewLoginResult(trip client.LoginRoundTrip) loginTripResult {
	var result loginTripResult

	select {
	case result.err = <-trip.Error:
	case result.failure = <-trip.LoginFailure:
	case result.loggedInUser = <-trip.LoginSuccess:
	case result.createdUser = <-trip.CreateSuccess:
	}

	return result
}

func DescribeClientServerProtocol(c gospec.Context) {
	authDB := auth.NewStream(nil, nil, nil)

	createUser := func(conn mockConn, username, password string) (net.AuthenticatedUser, client.CreatedUser) {
		trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin(username, password)
		user, err := net.AuthenticateFrom(conn.server, authDB)
		c.Assume(err, IsNil)

		result := NewLoginResult(trip)

		c.Assume(result.err, IsNil)
		c.Assume(result.failure, Equals, net.UserLoginFailure{})
		c.Assume(result.loggedInUser, Equals, client.LoggedInUser{})

		return user, result.createdUser
	}

	conn := newMockConn()
	defer conn.close()

	c.Specify("an unauthenticated connection", func() {
		c.Specify("can create a new user", func() {
			authUser, createdUser := createUser(conn, "newUser", "password")
			c.Expect(authUser.Username, Equals, createdUser.Name)

			c.Specify("unless the user already exists", func() {
				trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin("newUser", "some other password")
				_, err := net.AuthenticateFrom(conn.server, authDB)
				c.Expect(err, Equals, net.ErrInvalidLoginCredentials)

				result := NewLoginResult(trip)
				c.Assume(result.err, IsNil)
				c.Assume(result.loggedInUser, Equals, client.LoggedInUser{})
				c.Assume(result.createdUser, Equals, client.CreatedUser{})
				c.Expect(result.failure.Name, Equals, "newUser")
			})
		})

		c.Specify("can log a user in", func() {
			createUser(conn, "username", "password")
			trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin("username", "password")
			authedUser, err := net.AuthenticateFrom(conn.server, authDB)
			c.Assume(err, IsNil)

			result := NewLoginResult(trip)
			c.Assume(result.err, IsNil)
			c.Assume(result.failure, Equals, net.UserLoginFailure{})
			c.Assume(result.createdUser, Equals, client.CreatedUser{})
			c.Expect(result.loggedInUser.Name, Equals, authedUser.Username)

			c.Specify("unless the password is invalid", func() {
				trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin("username", "invalid")
				_, err := net.AuthenticateFrom(conn.server, authDB)
				c.Expect(err, Equals, net.ErrInvalidLoginCredentials)

				result := NewLoginResult(trip)
				c.Assume(result.err, IsNil)
				c.Assume(result.loggedInUser, Equals, client.LoggedInUser{})
				c.Assume(result.createdUser, Equals, client.CreatedUser{})
				c.Expect(result.failure.Name, Equals, "username")
			})
		})
	})

	authenticatedUser, createdUser := createUser(conn, "jim", "jimisthebest11!")

	actorDB := newMockActorDB(map[string][]string{
		"jim": {
			"jim the slayer",
			"jim the destroyer",
			"jimmy shrimp steamer",
		},
	})
	defer actorDB.close()

	c.Specify("an authenticated connection", func() {
		c.Specify("receives a list of actors", func() {
			trip := createdUser.GetActors()
			c.Expect(net.SendActors(conn.server, actorDB.Get, authenticatedUser), IsNil)

			var err error = nil
			var selectConn client.SelectActorConn
			select {
			case err = <-trip.Error:
			case selectConn = <-trip.SelectActorConn:
			}

			c.Assume(err, IsNil)
			c.Expect(selectConn.Actors(), ContainsAll, []string{
				"jim the slayer",
				"jim the destroyer",
				"jimmy shrimp steamer",
			})
		})

		trip := createdUser.GetActors()
		c.Assume(net.SendActors(conn.server, actorDB.Get, authenticatedUser), IsNil)

		var err error = nil
		var selectConn client.SelectActorConn
		select {
		case err = <-trip.Error:
		case selectConn = <-trip.SelectActorConn:
		}
		c.Assume(err, IsNil)

		c.Specify("can create a new actor", func() {
			c.Assume(selectConn.Actors(), Not(Contains), []string{"jay"})
			trip := selectConn.SelectActor("jay")

			actor, err := net.SelectActorFrom(conn.server, actorDB.Select, authenticatedUser)
			c.Assume(err, IsNil)

			var selectedActor client.SelectedActorConn
			var createdActor client.SelectedActorConn
			select {
			case err = <-trip.Error:
			case selectedActor = <-trip.SelectedActor:
			case createdActor = <-trip.CreatedActor:
			}
			c.Assume(err, IsNil)
			c.Assume(selectedActor, IsNil)
			c.Assume(createdActor, Not(IsNil))

			expectedActor := filu.Actor{
				Username: "jim",
				Name:     "jay",
			}
			c.Expect(actor, Equals, expectedActor)
			c.Expect(createdActor.Actor(), Equals, expectedActor)
		})

		c.Specify("can select an actor", func() {
			trip := selectConn.SelectActor("jim the slayer")

			actor, err := net.SelectActorFrom(conn.server, actorDB.Select, authenticatedUser)
			c.Assume(err, IsNil)

			var selectedActor client.SelectedActorConn
			var createdActor client.SelectedActorConn
			select {
			case err = <-trip.Error:
			case selectedActor = <-trip.SelectedActor:
			case createdActor = <-trip.CreatedActor:
			}
			c.Assume(err, IsNil)
			c.Assume(selectedActor, Not(IsNil))
			c.Assume(createdActor, IsNil)

			expectedActor := filu.Actor{
				Username: "jim",
				Name:     "jim the slayer",
			}
			c.Expect(actor, Equals, expectedActor)
			c.Expect(selectedActor.Actor(), Equals, expectedActor)
		})
	})
}
<commit_msg>[filu/net/prototest] factor out boilerplate for select actor spec<commit_after>package prototest

import (
	"io"

	"github.com/ghthor/filu"
	"github.com/ghthor/filu/actor"
	"github.com/ghthor/filu/auth"
	"github.com/ghthor/filu/net"
	"github.com/ghthor/filu/net/client"

	"github.com/ghthor/gospec"
	. "github.com/ghthor/gospec"
)

type mockConn struct {
	pr [2]*io.PipeReader
	pw [2]*io.PipeWriter

	server, client net.Conn
}

type readWriter struct {
	io.Reader
	io.Writer
}

func newMockConn() mockConn {
	c := mockConn{}
	c.pr[0], c.pw[0] = io.Pipe()
	c.pr[1], c.pw[1] = io.Pipe()

	c.server = net.NewGobConn(readWriter{c.pr[0], c.pw[1]})
	c.client = net.NewGobConn(readWriter{c.pr[1], c.pw[0]})

	return c
}

func (c mockConn) close() {
	for _, r := range c.pr {
		r.Close()
	}

	for _, w := range c.pw {
		w.Close()
	}
}

type mockActorDB struct {
	Get    chan<- actor.GetActorsRequest
	Select chan<- actor.SelectionRequest
}

func (db mockActorDB) close() {
	close(db.Get)
	close(db.Select)
}

func newMockActorDB(actors map[string][]string) *mockActorDB {
	getCh := make(chan actor.GetActorsRequest)
	selCh := make(chan actor.SelectionRequest)
	db := &mockActorDB{
		Get:    getCh,
		Select: selCh,
	}

	getProc := actor.NewGetActorsRequestProcessor()

	actor.SelectionRequestSource(selCh).
		WriteToProcessor(actor.NewSelectionProcessor()).
		WriteTo(getProc).
		End()

	actor.GetActorsRequestSource(getCh).
		WriteToProcessor(getProc).
		End()

	for username, names := range actors {
		for _, name := range names {
			db.createActor(username, name)
		}
	}

	return db
}

func (db mockActorDB) createActor(username, actorname string) actor.CreatedActor {
	r := actor.NewSelectionRequest(filu.Actor{
		Username: username,
		Name:     actorname,
	})
	db.Select <- r
	return <-r.CreatedActor
}

type loginTripResult struct {
	err          error
	failure      net.UserLoginFailure
	loggedInUser client.LoggedInUser
	createdUser  client.CreatedUser
}

func NewLoginResult(trip client.LoginRoundTrip) loginTripResult {
	var result loginTripResult

	select {
	case result.err = <-trip.Error:
	case result.failure = <-trip.LoginFailure:
	case result.loggedInUser = <-trip.LoginSuccess:
	case result.createdUser = <-trip.CreateSuccess:
	}

	return result
}

type selectActorResult struct {
	err           error
	selectedActor client.SelectedActorConn
	createdActor  client.SelectedActorConn
}

func NewSelectActorResult(trip client.SelectActorRoundTrip) selectActorResult {
	var result selectActorResult

	select {
	case result.err = <-trip.Error:
	case result.selectedActor = <-trip.SelectedActor:
	case result.createdActor = <-trip.CreatedActor:
	}

	return result
}

func DescribeClientServerProtocol(c gospec.Context) {
	authDB := auth.NewStream(nil, nil, nil)

	createUser := func(conn mockConn, username, password string) (net.AuthenticatedUser, client.CreatedUser) {
		trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin(username, password)
		user, err := net.AuthenticateFrom(conn.server, authDB)
		c.Assume(err, IsNil)

		result := NewLoginResult(trip)

		c.Assume(result.err, IsNil)
		c.Assume(result.failure, Equals, net.UserLoginFailure{})
		c.Assume(result.loggedInUser, Equals, client.LoggedInUser{})

		return user, result.createdUser
	}

	conn := newMockConn()
	defer conn.close()

	c.Specify("an unauthenticated connection", func() {
		c.Specify("can create a new user", func() {
			authUser, createdUser := createUser(conn, "newUser", "password")
			c.Expect(authUser.Username, Equals, createdUser.Name)

			c.Specify("unless the user already exists", func() {
				trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin("newUser", "some other password")
				_, err := net.AuthenticateFrom(conn.server, authDB)
				c.Expect(err, Equals, net.ErrInvalidLoginCredentials)

				result := NewLoginResult(trip)
				c.Assume(result.err, IsNil)
				c.Assume(result.loggedInUser, Equals, client.LoggedInUser{})
				c.Assume(result.createdUser, Equals, client.CreatedUser{})
				c.Expect(result.failure.Name, Equals, "newUser")
			})
		})

		c.Specify("can log a user in", func() {
			createUser(conn, "username", "password")
			trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin("username", "password")
			authedUser, err := net.AuthenticateFrom(conn.server, authDB)
			c.Assume(err, IsNil)

			result := NewLoginResult(trip)
			c.Assume(result.err, IsNil)
			c.Assume(result.failure, Equals, net.UserLoginFailure{})
			c.Assume(result.createdUser, Equals, client.CreatedUser{})
			c.Expect(result.loggedInUser.Name, Equals, authedUser.Username)

			c.Specify("unless the password is invalid", func() {
				trip := client.NewUnauthenticatedConn(conn.client).AttemptLogin("username", "invalid")
				_, err := net.AuthenticateFrom(conn.server, authDB)
				c.Expect(err, Equals, net.ErrInvalidLoginCredentials)

				result := NewLoginResult(trip)
				c.Assume(result.err, IsNil)
				c.Assume(result.loggedInUser, Equals, client.LoggedInUser{})
				c.Assume(result.createdUser, Equals, client.CreatedUser{})
				c.Expect(result.failure.Name, Equals, "username")
			})
		})
	})

	authenticatedUser, createdUser := createUser(conn, "jim", "jimisthebest11!")

	actorDB := newMockActorDB(map[string][]string{
		"jim": {
			"jim the slayer",
			"jim the destroyer",
			"jimmy shrimp steamer",
		},
	})
	defer actorDB.close()

	c.Specify("an authenticated connection", func() {
		c.Specify("receives a list of actors", func() {
			trip := createdUser.GetActors()
			c.Expect(net.SendActors(conn.server, actorDB.Get, authenticatedUser), IsNil)

			var err error = nil
			var selectConn client.SelectActorConn
			select {
			case err = <-trip.Error:
			case selectConn = <-trip.SelectActorConn:
			}

			c.Assume(err, IsNil)
			c.Expect(selectConn.Actors(), ContainsAll, []string{
				"jim the slayer",
				"jim the destroyer",
				"jimmy shrimp steamer",
			})
		})

		trip := createdUser.GetActors()
		c.Assume(net.SendActors(conn.server, actorDB.Get, authenticatedUser), IsNil)

		var err error = nil
		var selectConn client.SelectActorConn
		select {
		case err = <-trip.Error:
		case selectConn = <-trip.SelectActorConn:
		}
		c.Assume(err, IsNil)

		c.Specify("can create a new actor", func() {
			c.Assume(selectConn.Actors(), Not(Contains), []string{"jay"})
			trip := selectConn.SelectActor("jay")

			actor, err := net.SelectActorFrom(conn.server, actorDB.Select, authenticatedUser)
			c.Assume(err, IsNil)

			result := NewSelectActorResult(trip)
			c.Assume(result.err, IsNil)
			c.Assume(result.selectedActor, IsNil)
			c.Assume(result.createdActor, Not(IsNil))

			expectedActor := filu.Actor{
				Username: "jim",
				Name:     "jay",
			}
			c.Expect(actor, Equals, expectedActor)
			c.Expect(result.createdActor.Actor(), Equals, expectedActor)
		})

		c.Specify("can select an actor", func() {
			trip := selectConn.SelectActor("jim the slayer")

			actor, err := net.SelectActorFrom(conn.server, actorDB.Select, authenticatedUser)
			c.Assume(err, IsNil)

			result := NewSelectActorResult(trip)
			c.Assume(result.err, IsNil)
			c.Assume(result.selectedActor, Not(IsNil))
			c.Assume(result.createdActor, IsNil)

			expectedActor := filu.Actor{
				Username: "jim",
				Name:     "jim the slayer",
			}
			c.Expect(actor, Equals, expectedActor)
			c.Expect(result.selectedActor.Actor(), Equals, expectedActor)
		})
	})
}
<|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.

// Command memmodel is a memory model model checker.
//
// memmodel compares the relative strengths of different memory models
// using model checking techniques. It determines (up to typical
// limitations of model checking) which memory models are equivalent,
// stronger, and weaker than others, and produces this partial order
// as well as example programs that demonstrate the differences
// between non-equivalent memory models.
//
//
// Output
//
// memmodel generates a dot graph showing the partial order of memory
// models. Each node shows a set of equivalently strong memory models
// and edges point from the stronger models to the weaker models.
//
// TODO: Do a better job of outputting example programs.
//
//
// Supported memory models
//
// memmodel supports strict consistency (SC), x86-style total store
// order (TSO), acquire/release, and unordered memory models.
//
// Some of these memory models have two different, but equivalent
// specification strategies. Any model followed by "(HB)" is specified
// as a set rules for constructing a happens-before graph. Otherwise,
// the model is specified as an non-deterministic operational machine
// (e.g., TSO is implemented in terms of store buffers and store
// buffer forwarding). Operational machines tend to be easier to
// reason about, but the happens-before model is extremely flexible.
// Having both helps ensure that our specifications are what we
// intended.
//
// Likewise, some models have options. The operational implementation
// of TSO supports optional memory fences around loads and stores.
//
//
// How it works
//
// memmodel generates a large number of "litmus test" programs, where
// each program consists of a set of threads reading and writing
// shared variables. For each program, it determines all permissible
// outcomes under each memory model. If an outcome is permitted by
// memory model A but not memory model B, then A is weaker than B.
package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"strings"
)

type Model interface {
	Eval(p *Prog, outcomes *OutcomeSet)
	String() string
}

var models = []Model{
	SCModel{},
	TSOModel{},
	TSOModel{StoreMFence: true},
	TSOModel{MFenceLoad: true},
	HBModel{HBSC{}},
	HBModel{HBTSO{}},
	HBModel{HBAcqRel{}},
	HBModel{HBUnordered{}},
}

// TODO: Make the operation mode a flag. Also have a mode for only
// showing where the models differ.
const showProgs = false

func main() {
	flagOut := flag.String("o", "", "continuously write model graph to `output` dot file")
	flagNoSimplify := flag.Bool("no-simplify", false, "disable graph simplification")
	flag.Parse()
	if flag.NArg() > 0 {
		flag.Usage()
		os.Exit(2)
	}

	// counterexamples[i][j] gives an example program where model
	// i permits outcomes that model j does not.
	counterexamples := make([][]Prog, len(models))
	for i := range counterexamples {
		counterexamples[i] = make([]Prog, len(models))
	}

	n := 0
	outcomes := make([]OutcomeSet, len(models))
	for p := range GenerateProgs() {
		if !showProgs && n%10 == 0 {
			fmt.Fprintf(os.Stderr, "\r%d progs", n)
		}
		n++

		for i, model := range models {
			model.Eval(&p, &outcomes[i])
		}

		if showProgs {
			fmt.Println(&p)
			names := []string{}
			for _, model := range models {
				names = append(names, model.String())
			}
			printOutcomeTable(os.Stdout, names, outcomes)
			fmt.Println()
		}

		for i := range counterexamples {
			for j := range counterexamples[i] {
				if i == j {
					continue
				}
				if counterexamples[i][j].Threads[0].Ops[0].Type != OpExit {
					// Already have a counterexample.
					continue
				}
				if outcomes[i] == outcomes[j] {
					continue
				}
				if outcomes[i].Contains(&outcomes[j]) {
					// Model i permits outcomes
					// that model j does not. (i
					// is weaker than j.)
					counterexamples[i][j] = p
				}
				// TODO: Prefer smaller
				// counterexamples.
			}
		}

		if n%100 == 0 && *flagOut != "" {
			// dot uses inotify wrong, so it doesn't
			// notice if we write to a temp file and
			// rename it over the output file.
			f, err := os.Create(*flagOut)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			writeModelGraph(f, counterexamples, !*flagNoSimplify)
			f.Close()
		}
	}
	fmt.Fprintf(os.Stderr, "\r%d progs\n", n)

	f := os.Stdout
	if *flagOut != "" {
		var err error
		f, err = os.Create(*flagOut)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		defer f.Close()
	}
	writeModelGraph(f, counterexamples, !*flagNoSimplify)
}

func writeModelGraph(w io.Writer, counterexamples [][]Prog, simplify bool) {
	fmt.Fprintln(w, "digraph memmodel {")
	if simplify {
		fmt.Fprintln(w, "label=\"A -> B means A is stronger than B\";")
	} else {
		fmt.Fprintln(w, "label=\"A -> B means A is stronger than or equal to B\";")
	}

	// Create Graph.
	g := new(Graph)
	nodes := []*GNode{}
	for _, model := range models {
		nodes = append(nodes, g.NewNode(model.String()))
	}
	for i := range counterexamples {
		for j, p := range counterexamples[i] {
			if i == j {
				continue
			}
			if p.Threads[0].Ops[0].Type == OpExit {
				// No counterexample. Model i is
				// stronger than or equal to model j.
				g.Edge(nodes[i], nodes[j])
			} else {
				// Print the counter example. Model i
				// is weaker than model j.
				fmt.Fprintf(w, "# %q is weaker than %q;\n", models[i], models[j])
				fmt.Fprintln(w, "# "+strings.Replace(p.String(), "\n", "\n# ", -1))
				// TODO: Print an example of why.
			}
		}
	}

	if simplify {
		// Reduce equivalence classes to single nodes. Because
		// this is currently a non-strict partial order,
		// maximal cliques correspond to equivalence classes
		// and are unambiguous. This makes the graph a strict
		// partial order.
		cliques := g.MaximalCliques()
		g = g.CollapseNodes(cliques)
		// Now that we have a strict partial order (a DAG),
		// remove edges that are implied by other edges.
		g.TransitiveReduction()
	}

	// Print graph.
	g.ToDot(w, "")

	fmt.Fprintln(w, "}")
}
<commit_msg>memmodel: flags for outputting example programs and outcomes<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.

// Command memmodel is a memory model model checker.
//
// memmodel compares the relative strengths of different memory models
// using model checking techniques. It determines (up to typical
// limitations of model checking) which memory models are equivalent,
// stronger, and weaker than others, and produces this partial order
// as well as example programs that demonstrate the differences
// between non-equivalent memory models.
//
//
// Output
//
// memmodel supports several modes of output.
//
// With -graph, it generates a dot graph showing the partial order of
// memory models. Each node shows a set of equivalently strong memory
// models and edges point from the stronger models to the weaker
// models.
//
// With -examples, it outputs programs and outcomes showing the
// differences between non-equivalent memory models.
//
// With -all-progs, outputs all programs it generates along with the
// outcomes allowed by all of the models. This is mostly useful for
// debugging.
//
//
// Supported memory models
//
// memmodel supports strict consistency (SC), x86-style total store
// order (TSO), acquire/release, and unordered memory models.
//
// Some of these memory models have two different, but equivalent
// specification strategies. Any model followed by "(HB)" is specified
// as a set rules for constructing a happens-before graph. Otherwise,
// the model is specified as an non-deterministic operational machine
// (e.g., TSO is implemented in terms of store buffers and store
// buffer forwarding). Operational machines tend to be easier to
// reason about, but the happens-before model is extremely flexible.
// Having both helps ensure that our specifications are what we
// intended.
//
// Likewise, some models have options. The operational implementation
// of TSO supports optional memory fences around loads and stores.
//
//
// How it works
//
// memmodel generates a large number of "litmus test" programs, where
// each program consists of a set of threads reading and writing
// shared variables. For each program, it determines all permissible
// outcomes under each memory model. If an outcome is permitted by
// memory model A but not memory model B, then A is weaker than B.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"
)

type Model interface {
	Eval(p *Prog, outcomes *OutcomeSet)
	String() string
}

var models = []Model{
	SCModel{},
	TSOModel{},
	TSOModel{StoreMFence: true},
	TSOModel{MFenceLoad: true},
	HBModel{HBSC{}},
	HBModel{HBTSO{}},
	HBModel{HBAcqRel{}},
	HBModel{HBUnordered{}},
}

type Counterexample struct {
	p                Prog
	weaker, stronger Model
	wset, sset       OutcomeSet
}

func (c *Counterexample) Print(w io.Writer) {
	fmt.Fprintf(w, "%s is weaker than %s\n%s\n", c.weaker, c.stronger, &c.p)
	printOutcomeTable(w, []string{c.weaker.String(), c.stronger.String()}, []OutcomeSet{c.wset, c.sset})
}

func main() {
	flagGraph := flag.String("graph", "", "write model graph to `output` dot file")
	flagNoSimplify := flag.Bool("no-simplify", false, "disable graph simplification")
	// TODO: If we were to write the examples repeatedly like we
	// do for the graph, we could do the same graph reduction and
	// only print a minimal set of examples.
	flagExamples := flag.Bool("examples", false, "show examples where models differ")
	// TODO: These big tables would be pretty nice if we could
	// filter out the noise (e.g., only show them when models
	// disagree, order the columns from stronger to weaker,
	// collapse equivalent models).
	flagAllProgs := flag.Bool("all-progs", false, "show all programs and outcomes")
	flag.Parse()
	if flag.NArg() > 0 {
		flag.Usage()
		os.Exit(2)
	}

	// counterexamples[i][j] gives an example program where model
	// i permits outcomes that model j does not.
	counterexamples := make([][]*Counterexample, len(models))
	for i := range counterexamples {
		counterexamples[i] = make([]*Counterexample, len(models))
	}

	n := 0
	outcomes := make([]OutcomeSet, len(models))
	for p := range GenerateProgs() {
		if !(*flagAllProgs || *flagExamples) && n%10 == 0 {
			fmt.Fprintf(os.Stderr, "\r%d progs", n)
		}
		n++

		for i, model := range models {
			model.Eval(&p, &outcomes[i])
		}

		if *flagAllProgs {
			fmt.Println(&p)
			names := []string{}
			for _, model := range models {
				names = append(names, model.String())
			}
			printOutcomeTable(os.Stdout, names, outcomes)
			fmt.Println()
		}

		for i := range counterexamples {
			for j := range counterexamples[i] {
				if i == j {
					continue
				}
				if counterexamples[i][j] != nil {
					// Already have a counterexample.
					continue
				}
				if outcomes[i] == outcomes[j] {
					continue
				}
				if outcomes[i].Contains(&outcomes[j]) {
					// Model i permits outcomes
					// that model j does not. (i
					// is weaker than j.)
					c := &Counterexample{
						p, models[i], models[j],
						outcomes[i], outcomes[j],
					}
					counterexamples[i][j] = c
					if *flagExamples {
						c.Print(os.Stdout)
						fmt.Println()
					}
				}
				// TODO: Prefer smaller
				// counterexamples.
			}
		}

		if n%100 == 0 && *flagGraph != "" {
			// dot uses inotify wrong, so it doesn't
			// notice if we write to a temp file and
			// rename it over the output file.
			f, err := os.Create(*flagGraph)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			writeModelGraph(f, counterexamples, !*flagNoSimplify)
			f.Close()
		}
	}
	fmt.Fprintf(os.Stderr, "\r%d progs\n", n)

	// Write final graph.
	if *flagGraph != "" {
		f, err := os.Create(*flagGraph)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		defer f.Close()
		writeModelGraph(f, counterexamples, !*flagNoSimplify)
	}
}

func writeModelGraph(w io.Writer, counterexamples [][]*Counterexample, simplify bool) {
	fmt.Fprintln(w, "digraph memmodel {")
	if simplify {
		fmt.Fprintln(w, "label=\"A -> B means A is stronger than B\";")
	} else {
		fmt.Fprintln(w, "label=\"A -> B means A is stronger than or equal to B\";")
	}

	// Create Graph.
	g := new(Graph)
	nodes := []*GNode{}
	for _, model := range models {
		nodes = append(nodes, g.NewNode(model.String()))
	}
	for i := range counterexamples {
		for j, ce := range counterexamples[i] {
			if i == j {
				continue
			}
			if ce == nil {
				// No counterexample. Model i is
				// stronger than or equal to model j.
				g.Edge(nodes[i], nodes[j])
			} else {
				var buf bytes.Buffer
				// Model i is weaker than model j.
				// Print the counter example.
				ce.Print(&buf)
				fmt.Fprintf(w, "# %s\n", strings.Replace(buf.String(), "\n", "\n# ", -1))
			}
		}
	}

	if simplify {
		// Reduce equivalence classes to single nodes. Because
		// this is currently a non-strict partial order,
		// maximal cliques correspond to equivalence classes
		// and are unambiguous. This makes the graph a strict
		// partial order.
		cliques := g.MaximalCliques()
		g = g.CollapseNodes(cliques)
		// Now that we have a strict partial order (a DAG),
		// remove edges that are implied by other edges.
		g.TransitiveReduction()
	}

	// Print graph.
	g.ToDot(w, "")

	fmt.Fprintln(w, "}")
}
<|endoftext|>


<commit_before>package htpasswd_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/http/httptest"
	"net/url"
	"os"
	"path/filepath"
	"testing"
	"time"

	htpasswd "github.com/antifuchs/htpasswd-login"
)

type timer struct {
	at time.Time
}

func (t *timer) now() time.Time {
	return t.at
}

var _ htpasswd.Timesource = (&timer{}).now

func service(t *testing.T, ti *timer) (*htpasswd.Service, string, *httptest.Server) {
	dir, err := ioutil.TempDir("/tmp", "htpasswd-test")
	if err != nil {
		t.Fatal(err)
	}
	srv := &htpasswd.Service{
		Now:            ti.now,
		SessionDir:     dir,
		Htpasswd:       "example/htpasswd",
		CookieLifetime: time.Duration(1000) * time.Second,
		Secure:         false,
	}
	ts := httptest.NewServer(srv.Mux())
	u, err := url.Parse(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	srv.Domain = u.Host
	return srv, dir, ts
}

func TestGoodLogin(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Now()}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Errorf("Login should have succeeded: %v", resp)
	}
	t.Log(resp.Cookies())
	if len(resp.Cookies()) == 0 || resp.Cookies()[0].Value == "nope" {
		t.Errorf("I bad cookies: %#v", resp.Cookies())
	}

	u, _ := url.Parse(ts.URL)
	t.Log(cj.Cookies(u))

	resp, err = cl.Get(ts.URL + "/auth")
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Errorf("Should be authenticated, am not: %v", resp)
	}
}

func TestBadLogin(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}

	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "wrongpassword")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("Should have failed: %v", resp)
	}
}

func TestExpiredSession(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	srv, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Should be authenticated, am not: %v", resp)
	}

	ti.at = ti.at.Add(time.Duration(5) * time.Second).Add(srv.CookieLifetime)
	resp, err = cl.Get(ts.URL + "/auth")
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode == http.StatusOK {
		t.Errorf("Should no longer be authenticated, but I am: %v and %v", resp, cj)
	}
}

func TestBadDomain(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	otherURL, _ := url.Parse(ts.URL)

	// Replace "127.0.0.1" from the test server with "localhost" -
	// it's the same host (usually), but a different name.
	// NOTE: This assumes that local DNS resolution for
	// "localhost" works correctly; if yours doesn't, this test
	// will fail:
	otherURL.Host = fmt.Sprintf("%s:%s", "localhost", otherURL.Port())
	resp, err := cl.PostForm(otherURL.String()+"/login/", params)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Should be authenticated, am not: %v", resp)
	}

	resp, err = cl.Get(ts.URL + "/auth")
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode == http.StatusOK {
		t.Errorf("Should not be authenticated under this domain, but I am: %v and %v", resp, cj)
	}
}

func TestLogout(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)
	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	_, err = cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}

	// redirects god-knows-where, so no error checking:
	cl.PostForm(ts.URL+"/logout", url.Values{})

	resp, err := cl.Get(ts.URL + "/auth")
	if resp.StatusCode != http.StatusUnauthorized {
		t.Errorf("Should be unauthenticated, am not: %v", resp)
	}
}

func TestMalice(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	srv, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)
	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Should be authenticated, am not: %v", resp)
	}
	session := resp.Cookies()[0].Value
	u, _ := url.Parse(ts.URL)
	_, err = srv.ValidatedSessionFromStorage(dir+"/"+session, u.Host)
	if err == nil {
		t.Error(dir)
	}

	relative := filepath.Join("../", filepath.Base(dir), session)
	_, err = srv.ValidatedSessionFromStorage(relative, u.Host)
	if err == nil {
		t.Error("relative", relative)
	}

	slashes := "////" + dir + "/" + session
	if _, err := os.Stat(slashes); os.IsNotExist(err) {
		t.Error("slashes file doesn't exist")
	}
	_, err = srv.ValidatedSessionFromStorage("////"+dir+"/"+session, u.Host)
	if err == nil {
		t.Error("/////")
	}
}
<commit_msg>Fix test for go 1.7<commit_after>package htpasswd_test

import (
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/http/httptest"
	"net/url"
	"os"
	"path/filepath"
	"testing"
	"time"

	"strings"

	htpasswd "github.com/antifuchs/htpasswd-login"
)

type timer struct {
	at time.Time
}

func (t *timer) now() time.Time {
	return t.at
}

var _ htpasswd.Timesource = (&timer{}).now

func service(t *testing.T, ti *timer) (*htpasswd.Service, string, *httptest.Server) {
	dir, err := ioutil.TempDir("/tmp", "htpasswd-test")
	if err != nil {
		t.Fatal(err)
	}
	srv := &htpasswd.Service{
		Now:            ti.now,
		SessionDir:     dir,
		Htpasswd:       "example/htpasswd",
		CookieLifetime: time.Duration(1000) * time.Second,
		Secure:         false,
	}
	ts := httptest.NewServer(srv.Mux())
	u, err := url.Parse(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	srv.Domain = u.Host
	return srv, dir, ts
}

func TestGoodLogin(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Now()}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Errorf("Login should have succeeded: %v", resp)
	}
	t.Log(resp.Cookies())
	if len(resp.Cookies()) == 0 || resp.Cookies()[0].Value == "nope" {
		t.Errorf("I bad cookies: %#v", resp.Cookies())
	}

	u, _ := url.Parse(ts.URL)
	t.Log(cj.Cookies(u))

	resp, err = cl.Get(ts.URL + "/auth")
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Errorf("Should be authenticated, am not: %v", resp)
	}
}

func TestBadLogin(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}

	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "wrongpassword")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusForbidden {
		t.Errorf("Should have failed: %v", resp)
	}
}

func TestExpiredSession(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	srv, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Should be authenticated, am not: %v", resp)
	}

	ti.at = ti.at.Add(time.Duration(5) * time.Second).Add(srv.CookieLifetime)
	resp, err = cl.Get(ts.URL + "/auth")
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode == http.StatusOK {
		t.Errorf("Should no longer be authenticated, but I am: %v and %v", resp, cj)
	}
}

func TestBadDomain(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)

	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")

	// Replace "127.0.0.1" from the test server with "localhost" -
	// it's the same host (usually), but a different name.
	// NOTE: This assumes that local DNS resolution for
	// "localhost" works correctly; if yours doesn't, this test
	// will fail:
	otherURL := strings.Replace(ts.URL, "127.0.0.1", "localhost", 1)
	resp, err := cl.PostForm(otherURL+"/login/", params)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Should be authenticated, am not: %v", resp)
	}

	resp, err = cl.Get(ts.URL + "/auth")
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode == http.StatusOK {
		t.Errorf("Should not be authenticated under this domain, but I am: %v and %v", resp, cj)
	}
}

func TestLogout(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	_, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)
	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	_, err = cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}

	// redirects god-knows-where, so no error checking:
	cl.PostForm(ts.URL+"/logout", url.Values{})

	resp, err := cl.Get(ts.URL + "/auth")
	if resp.StatusCode != http.StatusUnauthorized {
		t.Errorf("Should be unauthenticated, am not: %v", resp)
	}
}

func TestMalice(t *testing.T) {
	t.Parallel()
	ti := &timer{at: time.Unix(0, 0)}
	srv, dir, ts := service(t, ti)
	defer ts.Close()
	defer os.RemoveAll(dir)
	cj, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	cl := http.Client{Jar: cj}
	params := url.Values{}
	params.Set("login", "test@example.com")
	params.Set("password", "test")
	resp, err := cl.PostForm(ts.URL+"/login/", params)
	if err != nil {
		t.Error(err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("Should be authenticated, am not: %v", resp)
	}
	session := resp.Cookies()[0].Value
	u, _ := url.Parse(ts.URL)
	_, err = srv.ValidatedSessionFromStorage(dir+"/"+session, u.Host)
	if err == nil {
		t.Error(dir)
	}

	relative := filepath.Join("../", filepath.Base(dir), session)
	_, err = srv.ValidatedSessionFromStorage(relative, u.Host)
	if err == nil {
		t.Error("relative", relative)
	}

	slashes := "////" + dir + "/" + session
	if _, err := os.Stat(slashes); os.IsNotExist(err) {
		t.Error("slashes file doesn't exist")
	}
	_, err = srv.ValidatedSessionFromStorage("////"+dir+"/"+session, u.Host)
	if err == nil {
		t.Error("/////")
	}
}
<|endoftext|>


<commit_before>package deployment

import (
	"errors"
	"reflect"
	"time"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/runtime"
)

// ManifestStep implements a deployment step
type ManifestStep struct {
	object runtime.Object
}

var _ Step = &ManifestStep{}

// NewManifestStep creates a default step
func NewManifestStep(object runtime.Object) Step {
	return &ManifestStep{
		object: object,
	}
}

func compareContainers(a, b v1.Container) bool {
	return a.Name == b.Name && a.Image == b.Image &&
		reflect.DeepEqual(a.Command, b.Command) &&
		reflect.DeepEqual(a.Args, b.Args) && a.WorkingDir == b.WorkingDir &&
		reflect.DeepEqual(a.Ports, b.Ports) &&
		reflect.DeepEqual(a.Env, b.Env) &&
		reflect.DeepEqual(a.Resources, b.Resources) &&
		a.ImagePullPolicy == b.ImagePullPolicy
}

func compareContainerLists(a, b []v1.Container) bool {
	aMap := map[string]v1.Container{}
	bMap := map[string]v1.Container{}

	for _, c := range a {
		aMap[c.Name] = c
	}
	for _, c := range b {
		bMap[c.Name] = c
	}

	if len(aMap) != len(bMap) {
		return false
	}

	for name, ac := range aMap {
		bc, ok := bMap[name]
		if !ok {
			return false
		}
		if !compareContainers(ac, bc) {
			return false
		}
	}
	return true
}

func comparePodSpecs(a, b v1.PodSpec) bool {
	if len(a.Containers) != len(b.Containers) {
		return false
	}
	if !compareContainerLists(a.Containers, b.Containers) {
		return false
	}
	return reflect.DeepEqual(a.ImagePullSecrets, b.ImagePullSecrets)
}

func comparePods(a, b *v1.Pod) bool {
	return reflect.DeepEqual(a.ObjectMeta, b.ObjectMeta) &&
		comparePodSpecs(a.Spec, b.Spec)
}

func compareRCs(a, b *v1.ReplicationController) bool {
	if a.ObjectMeta.Name == "" {
		return false
	}
	return reflect.DeepEqual(a.ObjectMeta, b.ObjectMeta) &&
		reflect.DeepEqual(a.Spec.Replicas, b.Spec.Replicas) &&
		reflect.DeepEqual(a.Spec.Selector, b.Spec.Selector) &&
		reflect.DeepEqual(a.Spec.Template.ObjectMeta, b.Spec.Template.ObjectMeta) &&
		comparePodSpecs(a.Spec.Template.Spec, b.Spec.Template.Spec)
}

// Deploy executes the deployment of a step
func (s *ManifestStep) Deploy() error {
	oGVK := s.object.GetObjectKind().GroupVersionKind()
	switch oGVK.Kind {
	case "ReplicationController":
		var o *v1.ReplicationController
		switch s.object.(type) {
		case *v1.ReplicationController:
			o = s.object.(*v1.ReplicationController)
		case *api.ReplicationController:
			rr := s.object.(*api.ReplicationController)
			if err := scheme.Convert(rr, o); err != nil {
				glog.Error("API object conversion failed.")
				return err
			}
		}
		rc, err := client.ReplicationControllers(namespace).Get(o.ObjectMeta.Name)
		if err == nil && rc != nil {
			if compareRCs(rc, o) {
				glog.Info("Existing RC is identical, skipping deployment")
				return nil
			}

			glog.Info("Deleting old replication controller: ", o.ObjectMeta.Name)
			err = client.ReplicationControllers(namespace).Delete(o.ObjectMeta.Name, nil)

			for k := 1; err == nil && k < 20; k++ {
				time.Sleep(200 * time.Millisecond) // Wait for Kubernetes to delete the resource
				_, err = client.ReplicationControllers(namespace).Get(o.ObjectMeta.Name)
			}
		}

		glog.Info("Creating new replication controller: ", o.ObjectMeta.Name)
		_, err = client.ReplicationControllers(namespace).Create(o)

		if err != nil {
			glog.Error("Create or Update failed: ", err)
			return err
		}
	case "Pod":
		o := s.object.(*v1.Pod)
		pod, err := client.Pods(namespace).Get(o.ObjectMeta.Name)

		if err == nil && pod != nil {
			if comparePods(pod, o) {
				glog.Info("Existing Pod is identical, skipping deployment")
				return nil
			}
			glog.Info("Deleting old pod", o.ObjectMeta.Name)
			err = client.Pods(namespace).Delete(o.ObjectMeta.Name, nil)

			for k := 1; err == nil && k < 20; k++ {
				time.Sleep(200 * time.Millisecond) // Wait for Kubernetes to delete the resource
				_, err = client.Pods(namespace).Get(o.ObjectMeta.Name)
			}
		}

		glog.Info("Creating new pod: ", o.ObjectMeta.Name)
		_, err = client.Pods(namespace).Create(o)
		if err != nil {
			glog.Info("Create or Update failed: ", err)
			return err
		}
	case "Service":
		o := s.object.(*v1.Service)
		service, err := client.Services(namespace).Get(o.ObjectMeta.Name)

		if err != nil {
			glog.Info("Creating new service: ", o.ObjectMeta.Name)
			_, err = client.Services(namespace).Create(o)
		} else {
			glog.Info("Updating service", o.ObjectMeta.Name)
			o.ObjectMeta.ResourceVersion = service.ObjectMeta.ResourceVersion
			o.Spec.ClusterIP = service.Spec.ClusterIP
			_, err = client.Services(namespace).Update(o)
		}
		if err != nil {
			glog.Info("Create or Update failed: ", err)
			return err
		}
	default:
		return errors.New("Kubernetes resource is not recognized: " + oGVK.Kind)
	}
	return nil
}

// Destroy deletes kubernetes resource
func (s *ManifestStep) Destroy() error {
	var err error
	oGVK := s.object.GetObjectKind().GroupVersionKind()
	meta, err := api.ObjectMetaFor(s.object)
	if err != nil {
		return err
	}
	switch oGVK.Kind {
	case "ReplicationController":
		err = client.ReplicationControllers(namespace).Delete(meta.Name, nil)
	case "Service":
		err = client.Services(namespace).Delete(meta.Name, nil)
	case "Pod":
		err = client.Pods(namespace).Delete(meta.Name, nil)
	}
	return err
}
<commit_msg>wait 2 seconds after deleting RCs (#93)<commit_after>package deployment

import (
	"errors"
	"reflect"
	"time"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/runtime"
)

// ManifestStep implements a deployment step
type ManifestStep struct {
	object runtime.Object
}

var _ Step = &ManifestStep{}

// NewManifestStep creates a default step
func NewManifestStep(object runtime.Object) Step {
	return &ManifestStep{
		object: object,
	}
}

func compareContainers(a, b v1.Container) bool {
	return a.Name == b.Name && a.Image == b.Image &&
		reflect.DeepEqual(a.Command, b.Command) &&
		reflect.DeepEqual(a.Args, b.Args) && a.WorkingDir == b.WorkingDir &&
		reflect.DeepEqual(a.Ports, b.Ports) &&
		reflect.DeepEqual(a.Env, b.Env) &&
		reflect.DeepEqual(a.Resources, b.Resources) &&
		a.ImagePullPolicy == b.ImagePullPolicy
}

func compareContainerLists(a, b []v1.Container) bool {
	aMap := map[string]v1.Container{}
	bMap := map[string]v1.Container{}

	for _, c := range a {
		aMap[c.Name] = c
	}
	for _, c := range b {
		bMap[c.Name] = c
	}

	if len(aMap) != len(bMap) {
		return false
	}

	for name, ac := range aMap {
		bc, ok := bMap[name]
		if !ok {
			return false
		}
		if !compareContainers(ac, bc) {
			return false
		}
	}
	return true
}

func comparePodSpecs(a, b v1.PodSpec) bool {
	if len(a.Containers) != len(b.Containers) {
		return false
	}
	if !compareContainerLists(a.Containers, b.Containers) {
		return false
	}
	return reflect.DeepEqual(a.ImagePullSecrets, b.ImagePullSecrets)
}

func comparePods(a, b *v1.Pod) bool {
	return reflect.DeepEqual(a.ObjectMeta, b.ObjectMeta) &&
		comparePodSpecs(a.Spec, b.Spec)
}

func compareRCs(a, b *v1.ReplicationController) bool {
	if a.ObjectMeta.Name == "" {
		return false
	}
	return reflect.DeepEqual(a.ObjectMeta, b.ObjectMeta) &&
		reflect.DeepEqual(a.Spec.Replicas, b.Spec.Replicas) &&
		reflect.DeepEqual(a.Spec.Selector, b.Spec.Selector) &&
		reflect.DeepEqual(a.Spec.Template.ObjectMeta, b.Spec.Template.ObjectMeta) &&
		comparePodSpecs(a.Spec.Template.Spec, b.Spec.Template.Spec)
}

// Deploy executes the deployment of a step
func (s *ManifestStep) Deploy() error {
	oGVK := s.object.GetObjectKind().GroupVersionKind()
	switch oGVK.Kind {
	case "ReplicationController":
		var o *v1.ReplicationController
		switch s.object.(type) {
		case *v1.ReplicationController:
			o = s.object.(*v1.ReplicationController)
		case *api.ReplicationController:
			rr := s.object.(*api.ReplicationController)
			if err := scheme.Convert(rr, o); err != nil {
				glog.Error("API object conversion failed.")
				return err
			}
		}
		rc, err := client.ReplicationControllers(namespace).Get(o.ObjectMeta.Name)
		if err == nil && rc != nil {
			if compareRCs(rc, o) {
				glog.Info("Existing RC is identical, skipping deployment")
				return nil
			}

			glog.Info("Deleting old replication controller: ", o.ObjectMeta.Name)
			err = client.ReplicationControllers(namespace).Delete(o.ObjectMeta.Name, nil)

			for k := 1; err == nil && k < 20; k++ {
				time.Sleep(200 * time.Millisecond) // Wait for Kubernetes to delete the resource
				_, err = client.ReplicationControllers(namespace).Get(o.ObjectMeta.Name)
			}
			time.Sleep(2 * time.Second) // Wait for Kubernetes to delete pods
		}

		glog.Info("Creating new replication controller: ", o.ObjectMeta.Name)
		_, err = client.ReplicationControllers(namespace).Create(o)

		if err != nil {
			glog.Error("Create or Update failed: ", err)
			return err
		}
	case "Pod":
		o := s.object.(*v1.Pod)
		pod, err := client.Pods(namespace).Get(o.ObjectMeta.Name)

		if err == nil && pod != nil {
			if comparePods(pod, o) {
				glog.Info("Existing Pod is identical, skipping deployment")
				return nil
			}
			glog.Info("Deleting old pod", o.ObjectMeta.Name)
			err = client.Pods(namespace).Delete(o.ObjectMeta.Name, nil)

			for k := 1; err == nil && k < 20; k++ {
				time.Sleep(200 * time.Millisecond) // Wait for Kubernetes to delete the resource
				_, err = client.Pods(namespace).Get(o.ObjectMeta.Name)
			}
		}

		glog.Info("Creating new pod: ", o.ObjectMeta.Name)
		_, err = client.Pods(namespace).Create(o)
		if err != nil {
			glog.Info("Create or Update failed: ", err)
			return err
		}
	case "Service":
		o := s.object.(*v1.Service)
		service, err := client.Services(namespace).Get(o.ObjectMeta.Name)

		if err != nil {
			glog.Info("Creating new service: ", o.ObjectMeta.Name)
			_, err = client.Services(namespace).Create(o)
		} else {
			glog.Info("Updating service", o.ObjectMeta.Name)
			o.ObjectMeta.ResourceVersion = service.ObjectMeta.ResourceVersion
			o.Spec.ClusterIP = service.Spec.ClusterIP
			_, err = client.Services(namespace).Update(o)
		}
		if err != nil {
			glog.Info("Create or Update failed: ", err)
			return err
		}
	default:
		return errors.New("Kubernetes resource is not recognized: " + oGVK.Kind)
	}
	return nil
}

// Destroy deletes kubernetes resource
func (s *ManifestStep) Destroy() error {
	var err error
	oGVK := s.object.GetObjectKind().GroupVersionKind()
	meta, err := api.ObjectMetaFor(s.object)
	if err != nil {
		return err
	}
	switch oGVK.Kind {
	case "ReplicationController":
		err = client.ReplicationControllers(namespace).Delete(meta.Name, nil)
	case "Service":
		err = client.Services(namespace).Delete(meta.Name, nil)
	case "Pod":
		err = client.Pods(namespace).Delete(meta.Name, nil)
	}
	return err
}
<|endoftext|>


<commit_before>package mesos

import (
	"encoding/json"
	"strings"
	"time"

	magent "github.com/Dataman-Cloud/swan/mesos/agent"
	"github.com/Dataman-Cloud/swan/mesosproto"
	"github.com/Dataman-Cloud/swan/types"

	log "github.com/Sirupsen/logrus"
)

const (
	defaultOfferTimeout  = 30 * time.Second
	defaultRefuseTimeout = 5 * time.Second
)

type eventHandler func(*mesosproto.Event)

func (s *Scheduler) subscribedHandler(event *mesosproto.Event) {
	var (
		ev = event.GetSubscribed()
		id = ev.FrameworkId
	)

	log.Printf("Subscription successful with frameworkId %s", id.GetValue())

	s.framework.Id = id

	if err := s.db.UpdateFrameworkId(id.GetValue()); err != nil {
		log.Errorf("update frameworkid got error:%s", err)
	}

	s.startReconcileLoop()
}

func (s *Scheduler) offersHandler(event *mesosproto.Event) {
	var (
		offers = event.Offers.Offers
	)

	log.Debugf("Receiving %d offer(s) from mesos", len(offers))

	for _, offer := range offers {
		agentId := offer.AgentId.GetValue()
		attrs := offer.GetAttributes()
		hostname := offer.GetHostname()

		a := s.getAgent(agentId)
		if a == nil {
			a = magent.NewAgent(agentId, hostname, attrs)
			s.addAgent(a)
		}

		s.addOffer(offer)
	}
}

func (s *Scheduler) rescindedHandler(event *mesosproto.Event) {
	var (
		offerId = event.GetRescind().OfferId.GetValue()
	)

	log.Debugln("Receiving rescind msg for offer ", offerId)

	for _, agent := range s.getAgents() {
		if offer := agent.GetOffer(offerId); offer != nil {
			s.removeOffer(offer)
			break
		}
	}
}

// we use this in task update event handler to ensure removed db objects'
// dns & proxy records could be cleaned up
func (s *Scheduler) broadCastCleanupEvents(appId, taskId string) {
	log.Debugln("broadcast task unhealthy evnets for not exists app or tasks")

	taskEv := &types.TaskEvent{
		Type:           types.EventTypeTaskUnhealthy,
		AppID:          appId,
		TaskID:         taskId,
		GatewayEnabled: true, // set true to clean up agent's potential outdated proxy records
	}

	if err := s.eventmgr.broadcast(taskEv); err != nil {
		log.Errorln("broadcast task event got error:", err)
	}

	if err := s.broadcastEventRecords(taskEv); err != nil {
		log.Errorln("broadcast to sync proxy & dns records error:", err)
	}
}

func (s *Scheduler) updateHandler(event *mesosproto.Event) {
	var (
		status  = event.GetUpdate().GetStatus()
		state   = status.GetState()
		taskId  = status.TaskId.GetValue()
		healthy = status.GetHealthy()
		data    = status.GetData()
	)

	log.Debugf("Received status update %s(%v) for task:%s, reason:%s, message:%s",
		status.GetState(), healthy, taskId, status.GetReason().String(), status.GetMessage())

	// get appId
	var appId string
	parts := strings.SplitN(taskId, ".", 3)
	if len(parts) >= 3 {
		appId = parts[2]
	}

	// obtain db app op status
	ops, err := s.db.GetAppOpStatus(appId)
	if err != nil {
		log.Errorf("find app op status got error: %v. app %s", err, appId)
		return
	}

	// obtain db task & update
	task, err := s.db.GetTask(appId, taskId)
	if err != nil {
		s.broadCastCleanupEvents(appId, taskId)
		log.Errorf("find task got error: %v. task %s", err, taskId)
		return
	}

	// issue: https://issues.apache.org/jira/browse/MESOS-7906
	if task.ContainerID == "" && state == mesosproto.TaskState_TASK_RUNNING {
		// get container id & name & ip
		var cinfos []struct {
			ID              string                 `json:"Id"`
			Name            string                 `json:"Name"`
			NetworkSettings *types.NetworkSettings `json:"NetworkSettings"`
		}
		json.Unmarshal(data, &cinfos)

		if len(cinfos) > 0 {
			if cid := cinfos[0].ID; cid != "" {
				task.ContainerID = cid
			}

			if cname := cinfos[0].Name; cname != "" {
				task.ContainerName = cname
			}

			if task.IP == "" {
				if settings := cinfos[0].NetworkSettings; settings != nil {
					if net := settings.Networks; net != nil && len(net) > 0 {
						for _, cfg := range net {
							if cfg.IPAMConfig != nil {
								task.IP = cfg.IPAMConfig.IPv4Address
							} else {
								task.IP = cfg.IPAddress
							}
							break
						}
					}
				}
			}
		}
	}

	var (
		previousHealthy = task.Healthy // previous healthy
		previousStatus  = task.Status  // previous status
	)

	// set healthy
	if task.Healthy != types.TaskHealthyUnset {
		task.Healthy = types.TaskUnHealthy
		if healthy {
			task.Healthy = types.TaskHealthy
		}
	}

	// set status
	task.Status = state.String()
	if state != mesosproto.TaskState_TASK_RUNNING {
		task.ErrMsg = status.GetReason().String() + ":" + status.GetMessage()
	}

	// reset task failed retry time to zero
	if state == mesosproto.TaskState_TASK_RUNNING {
		task.Retries = 0
	}

	// memo db update db task
	if err := s.db.UpdateTask(appId, task); err != nil {
		if s.db.IsErrNotFound(err) {
			s.broadCastCleanupEvents(appId, taskId)
		}
		log.Errorf("update task %d db status to %s error: %v", taskId, state.String(), err)
		return
	}

	// obtain db task version
	ver, err := s.db.GetVersion(appId, task.Version) // task corresponding version
	if err != nil {
		s.broadCastCleanupEvents(appId, taskId)
		log.Errorf("find task version got error: %v. task %s, version %s", err, task.ID, task.Version)
		return
	}

	// if task terminated
	if IsTaskDone(status) && state != mesosproto.TaskState_TASK_RUNNING {
		s.broadCastCleanupEvents(appId, taskId)
	}

	// if task healthy / status changed
	var healthyChange bool
	switch previousHealthy {
	case types.TaskHealthyUnset:
		healthyChange = previousStatus != task.Status
	default:
		healthyChange = previousHealthy != task.Healthy
	}

	// broadcasting task events
	log.Debugf("task %s healthy & status: %s (%s) --> %s (%s) --> changed=%v",
		taskId, previousHealthy, previousStatus, task.Healthy, task.Status, healthyChange)

	if healthyChange { // skip on no-change
		evType := types.EventTypeTaskUnhealthy
		switch task.Healthy {
		case types.TaskHealthy:
			evType = types.EventTypeTaskHealthy
		case types.TaskHealthyUnset:
			if task.Status == "TASK_RUNNING" {
				evType = types.EventTypeTaskHealthy
			}
		case types.TaskUnHealthy:
		}

		var (
			alias        string
			proxyEnabled bool
			listen       string
			sticky       bool
		)
		if ver.Proxy != nil {
			proxyEnabled = ver.Proxy.Enabled
			alias = ver.Proxy.Alias
			listen = ver.Proxy.Listen
			sticky = ver.Proxy.Sticky
		}

		var taskPort uint64
		if len(task.Ports) > 0 { // currently only support the first port within proxy & events
			taskPort = task.Ports[0]
		}

		taskEv := &types.TaskEvent{
			Type:           evType,
			AppID:          appId,
			AppAlias:       alias,
			AppListen:      listen,
			AppSticky:      sticky,
			TaskID:         taskId,
			IP:             task.IP,
			Port:           taskPort,
			Weight:         task.Weight,
			GatewayEnabled: proxyEnabled,
		}

		log.Debugln("sending task changed event", taskId)
		if err := s.eventmgr.broadcast(taskEv); err != nil {
			log.Errorln("broadcast task event got error:", err)
		}

		if err := s.broadcastEventRecords(taskEv); err != nil {
			log.Errorln("broadcast to sync proxy & dns records error:", err)
			// TODO: memo db task errmsg
		}
	}

	// FIXME enable reschedule only on app is running, creating, starting, scaling-up ...
	switch ops {
	case types.OpStatusNoop, types.OpStatusCreating, types.OpStatusStarting, types.OpStatusScalingUp:
	default:
		return
	}

	// reschedule failed tasks
	if state != mesosproto.TaskState_TASK_STAGING &&
		state != mesosproto.TaskState_TASK_STARTING &&
		state != mesosproto.TaskState_TASK_RUNNING {
		if task.Retries >= task.MaxRetries {
			// no more retry
			log.Debugln("task", taskId, "maxRetries:", task.MaxRetries, "retries:", task.Retries)
			return
		}

		if t := s.getPendingTask(taskId); t != nil {
			// task already being rescheduling.
			log.Debugln("task already in rescheduling", taskId)
			return
		}

		if err := s.db.DeleteTask(task.ID); err != nil {
			log.Errorf("updateHandler(): delete task failed: %s", err)
		}

		go s.rescheduleTask(appId, task)
	}
}

func (s *Scheduler) heartbeatHandler(event *mesosproto.Event) {
	log.Debugln("Receive heartbeat msg from mesos")
}

func (s *Scheduler) errHandler(event *mesosproto.Event) {
	ev := event.GetError()

	log.Debugf("Receive error msg %s", ev.GetMessage())
	s.reconnect()
}

func (s *Scheduler) failureHandler(event *mesosproto.Event) {
	var (
		ev      = event.GetFailure()
		agentId = ev.GetAgentId()
		execId  = ev.GetExecutorId()
		status  = ev.GetStatus()
	)

	if execId != nil {
		log.Debugf("Receive failure msg for executor %s terminated with status %d", execId.GetValue(), status)
		return
	}

	log.Debugf("Receive msg for agent %s removed.", agentId.GetValue())

}

func (s *Scheduler) messageHandler(event *mesosproto.Event) {
}
<commit_msg>adjust mesos health check state<commit_after>package mesos

import (
	"encoding/json"
	"strings"
	"time"

	magent "github.com/Dataman-Cloud/swan/mesos/agent"
	"github.com/Dataman-Cloud/swan/mesosproto"
	"github.com/Dataman-Cloud/swan/types"

	log "github.com/Sirupsen/logrus"
)

const (
	defaultOfferTimeout  = 30 * time.Second
	defaultRefuseTimeout = 5 * time.Second
)

type eventHandler func(*mesosproto.Event)

func (s *Scheduler) subscribedHandler(event *mesosproto.Event) {
	var (
		ev = event.GetSubscribed()
		id = ev.FrameworkId
	)

	log.Printf("Subscription successful with frameworkId %s", id.GetValue())

	s.framework.Id = id

	if err := s.db.UpdateFrameworkId(id.GetValue()); err != nil {
		log.Errorf("update frameworkid got error:%s", err)
	}

	s.startReconcileLoop()
}

func (s *Scheduler) offersHandler(event *mesosproto.Event) {
	var (
		offers = event.Offers.Offers
	)

	log.Debugf("Receiving %d offer(s) from mesos", len(offers))

	for _, offer := range offers {
		agentId := offer.AgentId.GetValue()
		attrs := offer.GetAttributes()
		hostname := offer.GetHostname()

		a := s.getAgent(agentId)
		if a == nil {
			a = magent.NewAgent(agentId, hostname, attrs)
			s.addAgent(a)
		}

		s.addOffer(offer)
	}
}

func (s *Scheduler) rescindedHandler(event *mesosproto.Event) {
	var (
		offerId = event.GetRescind().OfferId.GetValue()
	)

	log.Debugln("Receiving rescind msg for offer ", offerId)

	for _, agent := range s.getAgents() {
		if offer := agent.GetOffer(offerId); offer != nil {
			s.removeOffer(offer)
			break
		}
	}
}

// we use this in task update event handler to ensure removed db objects'
// dns & proxy records could be cleaned up
func (s *Scheduler) broadCastCleanupEvents(appId, taskId string) {
	log.Debugln("broadcast task unhealthy evnets for not exists app or tasks")

	taskEv := &types.TaskEvent{
		Type:           types.EventTypeTaskUnhealthy,
		AppID:          appId,
		TaskID:         taskId,
		GatewayEnabled: true, // set true to clean up agent's potential outdated proxy records
	}

	if err := s.eventmgr.broadcast(taskEv); err != nil {
		log.Errorln("broadcast task event got error:", err)
	}

	if err := s.broadcastEventRecords(taskEv); err != nil {
		log.Errorln("broadcast to sync proxy & dns records error:", err)
	}
}

func (s *Scheduler) updateHandler(event *mesosproto.Event) {
	var (
		status  = event.GetUpdate().GetStatus()
		state   = status.GetState()
		taskId  = status.TaskId.GetValue()
		healthy = status.GetHealthy()
		data    = status.GetData()
	)

	switch state {
	case mesosproto.TaskState_TASK_FINISHED,
		mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_KILLED,
		mesosproto.TaskState_TASK_ERROR,
		mesosproto.TaskState_TASK_LOST,
		mesosproto.TaskState_TASK_DROPPED,
		mesosproto.TaskState_TASK_UNREACHABLE,
		mesosproto.TaskState_TASK_GONE,
		mesosproto.TaskState_TASK_GONE_BY_OPERATOR,
		mesosproto.TaskState_TASK_UNKNOWN:

		healthy = false
	}

	log.Println("Received status update %s(%v) for task:%s, reason:%s, message:%s",
		status.GetState(), healthy, taskId, status.GetReason().String(), status.GetMessage())

	// get appId
	var appId string
	parts := strings.SplitN(taskId, ".", 3)
	if len(parts) >= 3 {
		appId = parts[2]
	}

	// obtain db app op status
	ops, err := s.db.GetAppOpStatus(appId)
	if err != nil {
		log.Errorf("find app op status got error: %v. app %s", err, appId)
		return
	}

	// obtain db task & update
	task, err := s.db.GetTask(appId, taskId)
	if err != nil {
		s.broadCastCleanupEvents(appId, taskId)
		log.Errorf("find task got error: %v. task %s", err, taskId)
		return
	}

	// issue: https://issues.apache.org/jira/browse/MESOS-7906
	if task.ContainerID == "" && state == mesosproto.TaskState_TASK_RUNNING {
		// get container id & name & ip
		var cinfos []struct {
			ID              string                 `json:"Id"`
			Name            string                 `json:"Name"`
			NetworkSettings *types.NetworkSettings `json:"NetworkSettings"`
		}
		json.Unmarshal(data, &cinfos)

		if len(cinfos) > 0 {
			if cid := cinfos[0].ID; cid != "" {
				task.ContainerID = cid
			}

			if cname := cinfos[0].Name; cname != "" {
				task.ContainerName = cname
			}

			if task.IP == "" {
				if settings := cinfos[0].NetworkSettings; settings != nil {
					if net := settings.Networks; net != nil && len(net) > 0 {
						for _, cfg := range net {
							if cfg.IPAMConfig != nil {
								task.IP = cfg.IPAMConfig.IPv4Address
							} else {
								task.IP = cfg.IPAddress
							}
							break
						}
					}
				}
			}
		}
	}

	var (
		previousHealthy = task.Healthy // previous healthy
		previousStatus  = task.Status  // previous status
	)

	// set healthy
	if task.Healthy != types.TaskHealthyUnset {
		task.Healthy = types.TaskUnHealthy
		if healthy {
			task.Healthy = types.TaskHealthy
		}
	}

	// set status
	task.Status = state.String()
	if state != mesosproto.TaskState_TASK_RUNNING {
		task.ErrMsg = status.GetReason().String() + ":" + status.GetMessage()
	}

	// reset task failed retry time to zero
	if state == mesosproto.TaskState_TASK_RUNNING {
		task.Retries = 0
	}

	// memo db update db task
	if err := s.db.UpdateTask(appId, task); err != nil {
		if s.db.IsErrNotFound(err) {
			s.broadCastCleanupEvents(appId, taskId)
		}
		log.Errorf("update task %d db status to %s error: %v", taskId, state.String(), err)
		return
	}

	// obtain db task version
	ver, err := s.db.GetVersion(appId, task.Version) // task corresponding version
	if err != nil {
		s.broadCastCleanupEvents(appId, taskId)
		log.Errorf("find task version got error: %v. task %s, version %s", err, task.ID, task.Version)
		return
	}

	// if task terminated
	if IsTaskDone(status) && state != mesosproto.TaskState_TASK_RUNNING {
		s.broadCastCleanupEvents(appId, taskId)
	}

	// if task healthy / status changed
	var healthyChange bool
	switch previousHealthy {
	case types.TaskHealthyUnset:
		healthyChange = previousStatus != task.Status
	default:
		healthyChange = previousHealthy != task.Healthy
	}

	// broadcasting task events
	log.Println("task %s healthy & status: %s (%s) --> %s (%s) --> changed=%v",
		taskId, previousHealthy, previousStatus, task.Healthy, task.Status, healthyChange)

	if healthyChange { // skip on no-change
		evType := types.EventTypeTaskUnhealthy
		switch task.Healthy {
		case types.TaskHealthy:
			evType = types.EventTypeTaskHealthy
		case types.TaskHealthyUnset:
			if task.Status == "TASK_RUNNING" {
				evType = types.EventTypeTaskHealthy
			}
		case types.TaskUnHealthy:
		}

		var (
			alias        string
			proxyEnabled bool
			listen       string
			sticky       bool
		)
		if ver.Proxy != nil {
			proxyEnabled = ver.Proxy.Enabled
			alias = ver.Proxy.Alias
			listen = ver.Proxy.Listen
			sticky = ver.Proxy.Sticky
		}

		var taskPort uint64
		if len(task.Ports) > 0 { // currently only support the first port within proxy & events
			taskPort = task.Ports[0]
		}

		taskEv := &types.TaskEvent{
			Type:           evType,
			AppID:          appId,
			AppAlias:       alias,
			AppListen:      listen,
			AppSticky:      sticky,
			TaskID:         taskId,
			IP:             task.IP,
			Port:           taskPort,
			Weight:         task.Weight,
			GatewayEnabled: proxyEnabled,
		}

		log.Debugln("sending task changed event", taskId)
		if err := s.eventmgr.broadcast(taskEv); err != nil {
			log.Errorln("broadcast task event got error:", err)
		}

		if err := s.broadcastEventRecords(taskEv); err != nil {
			log.Errorln("broadcast to sync proxy & dns records error:", err)
			// TODO: memo db task errmsg
		}
	}

	// FIXME enable reschedule only on app is running, creating, starting, scaling-up ...
	switch ops {
	case types.OpStatusNoop, types.OpStatusCreating, types.OpStatusStarting, types.OpStatusScalingUp:
	default:
		return
	}

	// reschedule failed tasks
	if state != mesosproto.TaskState_TASK_STAGING &&
		state != mesosproto.TaskState_TASK_STARTING &&
		state != mesosproto.TaskState_TASK_RUNNING {
		if task.Retries >= task.MaxRetries {
			// no more retry
			log.Debugln("task", taskId, "maxRetries:", task.MaxRetries, "retries:", task.Retries)
			return
		}

		if t := s.getPendingTask(taskId); t != nil {
			// task already being rescheduling.
			log.Debugln("task already in rescheduling", taskId)
			return
		}

		if err := s.db.DeleteTask(task.ID); err != nil {
			log.Errorf("updateHandler(): delete task failed: %s", err)
		}

		go s.rescheduleTask(appId, task)
	}
}

func (s *Scheduler) heartbeatHandler(event *mesosproto.Event) {
	log.Debugln("Receive heartbeat msg from mesos")
}

func (s *Scheduler) errHandler(event *mesosproto.Event) {
	ev := event.GetError()

	log.Debugf("Receive error msg %s", ev.GetMessage())
	s.reconnect()
}

func (s *Scheduler) failureHandler(event *mesosproto.Event) {
	var (
		ev      = event.GetFailure()
		agentId = ev.GetAgentId()
		execId  = ev.GetExecutorId()
		status  = ev.GetStatus()
	)

	if execId != nil {
		log.Debugf("Receive failure msg for executor %s terminated with status %d", execId.GetValue(), status)
		return
	}

	log.Debugf("Receive msg for agent %s removed.", agentId.GetValue())

}

func (s *Scheduler) messageHandler(event *mesosproto.Event) {
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"errors"
	"fmt"
	"net"
	"net/http"
	"strings"
)

type Server struct {
	Type           string `xml:"type,attr"`
	Hostname       string `xml:"hostname"`
	Port           uint16 `xml:"port"`
	SocketType     string `xml:"socketType"`
	Authentication string `xml:"authentication"`
	Username       string `xml:"username"`
}
type IncomingServer struct {
	XMLName struct{} `xml:"incomingServer"`

	Server
}
type OutgoingServer struct {
	XMLName struct{} `xml:"outgoingServer"`

	Server
}

type Provider struct {
	XMLName struct{} `xml:"emailProvider"`

	Id               string `xml:"id,attr"`
	Domain           string `xml:"domain"`
	DisplayName      string `xml:"displayName"`
	DisplayShortName string `xml:"displayShortName"`

	IncomingServers []IncomingServer
	OutgoingServers []OutgoingServer
}

type ClientConfig struct {
	XMLName struct{} `xml:"clientConfig"`

	Version   string `xml:"version,attr"`
	Providers []Provider
}

// Lookup the given service, protocol pair in the domain SRV records.
func lookup(service, proto, domain string) (string, uint16, error) {
	_, addresses, err := net.LookupSRV(service, proto, domain)

	if err != nil {
		return "", 0, err
	}
	if len(addresses) == 0 {
		return "", 0, errors.New("No SRV records available for the given domain")
	}

	return strings.Trim(addresses[0].Target, "."), addresses[0].Port, nil
}

// Generate an autoconfig XML document based on the information obtained from
// querying the domain SRV records.
func generate_xml(domain string) ([]byte, error) {
	// Incoming server.
	address_in, port_in, err := lookup("imaps", "tcp", domain)
	if err != nil {
		return nil, err
	}

	incoming := IncomingServer{}
	incoming.Type = "imap"
	incoming.Hostname = address_in
	incoming.Port = port_in
	incoming.SocketType = "STARTTLS"
	incoming.Authentication = "password-encrypted"
	incoming.Username = "%EMAILADDRESS%"

	// Outgoing server.
	address_out, port_out, err := lookup("submission", "tcp", domain)
	if err != nil {
		return nil, err
	}

	outgoing := OutgoingServer{}
	outgoing.Type = "smtp"
	outgoing.Hostname = address_out
	outgoing.Port = port_out
	outgoing.SocketType = "STARTTLS"
	outgoing.Authentication = "password-encrypted"
	outgoing.Username = "%EMAILADDRESS%"

	// Final data mangling.
	config := ClientConfig{
		Version: "1.1",
		Providers: []Provider{
			Provider{
				Id:               domain,
				Domain:           domain,
				DisplayName:      domain,
				DisplayShortName: domain,
				IncomingServers:  []IncomingServer{incoming},
				OutgoingServers:  []OutgoingServer{outgoing},
			},
		},
	}

	xmlconfig, err := xml.Marshal(&config)
	if err != nil {
		return nil, err
	}

	return xmlconfig, nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	xmlconfig, err := generate_xml("marshland.ovh")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, xml.Header, string(xmlconfig))
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":9000", nil)
}
<commit_msg>Changed settings to reflect the real server setup.<commit_after>package main

import (
	"encoding/xml"
	"errors"
	"fmt"
	"net"
	"net/http"
	"strings"
)

type Server struct {
	Type           string `xml:"type,attr"`
	Hostname       string `xml:"hostname"`
	Port           uint16 `xml:"port"`
	SocketType     string `xml:"socketType"`
	Authentication string `xml:"authentication"`
	Username       string `xml:"username"`
}
type IncomingServer struct {
	XMLName struct{} `xml:"incomingServer"`

	Server
}
type OutgoingServer struct {
	XMLName struct{} `xml:"outgoingServer"`

	Server
}

type Provider struct {
	XMLName struct{} `xml:"emailProvider"`

	Id               string `xml:"id,attr"`
	Domain           string `xml:"domain"`
	DisplayName      string `xml:"displayName"`
	DisplayShortName string `xml:"displayShortName"`

	IncomingServers []IncomingServer
	OutgoingServers []OutgoingServer
}

type ClientConfig struct {
	XMLName struct{} `xml:"clientConfig"`

	Version   string `xml:"version,attr"`
	Providers []Provider
}

// Lookup the given service, protocol pair in the domain SRV records.
func lookup(service, proto, domain string) (string, uint16, error) {
	_, addresses, err := net.LookupSRV(service, proto, domain)

	if err != nil {
		return "", 0, err
	}
	if len(addresses) == 0 {
		return "", 0, errors.New("No SRV records available for the given domain")
	}

	return strings.Trim(addresses[0].Target, "."), addresses[0].Port, nil
}

// Generate an autoconfig XML document based on the information obtained from
// querying the domain SRV records.
func generate_xml(domain string) ([]byte, error) {
	// Incoming server.
	address_in, port_in, err := lookup("imaps", "tcp", domain)
	if err != nil {
		return nil, err
	}

	incoming := IncomingServer{}
	incoming.Type = "imap"
	incoming.Hostname = address_in
	incoming.Port = port_in
	incoming.SocketType = "SSL"
	incoming.Authentication = "password-cleartext"
	incoming.Username = "%EMAILLOCALPART%"

	// Outgoing server.
	address_out, port_out, err := lookup("submission", "tcp", domain)
	if err != nil {
		return nil, err
	}

	outgoing := OutgoingServer{}
	outgoing.Type = "smtp"
	outgoing.Hostname = address_out
	outgoing.Port = port_out
	outgoing.SocketType = "SSL"
	outgoing.Authentication = "password-cleartext"
	outgoing.Username = "%EMAILLOCALPART%"

	// Final data mangling.
	config := ClientConfig{
		Version: "1.1",
		Providers: []Provider{
			Provider{
				Id:               domain,
				Domain:           domain,
				DisplayName:      domain,
				DisplayShortName: domain,
				IncomingServers:  []IncomingServer{incoming},
				OutgoingServers:  []OutgoingServer{outgoing},
			},
		},
	}

	xmlconfig, err := xml.Marshal(&config)
	if err != nil {
		return nil, err
	}

	return xmlconfig, nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	xmlconfig, err := generate_xml("marshland.ovh")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, xml.Header, string(xmlconfig))
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":9090", nil)
}
<|endoftext|>


<commit_before>// Copyright 2015 Matthew Holt and The Caddy 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 caddyauth

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"flag"
	"fmt"
	"os"
	"os/signal"

	"github.com/caddyserver/caddy/v2"
	caddycmd "github.com/caddyserver/caddy/v2/cmd"
	"golang.org/x/crypto/ssh/terminal"
)

func init() {
	caddycmd.RegisterCommand(caddycmd.Command{
		Name:  "hash-password",
		Func:  cmdHashPassword,
		Usage: "[--algorithm <name>] [--salt <string>] [--plaintext <password>]",
		Short: "Hashes a password and writes base64",
		Long: `
Convenient way to hash a plaintext password. The resulting
hash is written to stdout as a base64 string.

--plaintext, when omitted, will be read from stdin. If
Caddy is attached to a controlling tty, the plaintext will
not be echoed.

--algorithm may be bcrypt or scrypt. If script, the default
parameters are used.

Use the --salt flag for algorithms which require a salt to
be provided (scrypt).
`,
		Flags: func() *flag.FlagSet {
			fs := flag.NewFlagSet("hash-password", flag.ExitOnError)
			fs.String("algorithm", "bcrypt", "Name of the hash algorithm")
			fs.String("plaintext", "", "The plaintext password")
			fs.String("salt", "", "The password salt")
			return fs
		}(),
	})
}

func cmdHashPassword(fs caddycmd.Flags) (int, error) {
	var err error

	algorithm := fs.String("algorithm")
	plaintext := []byte(fs.String("plaintext"))
	salt := []byte(fs.String("salt"))

	if len(plaintext) == 0 {
		fd := int(os.Stdin.Fd())
		if terminal.IsTerminal(fd) {
			// ensure the terminal state is restored on SIGINT
			state, _ := terminal.GetState(fd)
			c := make(chan os.Signal)
			signal.Notify(c, os.Interrupt)
			go func() {
				<-c
				_ = terminal.Restore(fd, state)
				os.Exit(caddy.ExitCodeFailedStartup)
			}()
			defer signal.Stop(c)

			fmt.Fprint(os.Stderr, "Enter password: ")
			plaintext, err = terminal.ReadPassword(fd)
			fmt.Fprintln(os.Stderr)
			if err != nil {
				return caddy.ExitCodeFailedStartup, err
			}

			fmt.Fprint(os.Stderr, "Confirm password: ")
			confirmation, err := terminal.ReadPassword(fd)
			fmt.Fprintln(os.Stderr)
			if err != nil {
				return caddy.ExitCodeFailedStartup, err
			}

			if !bytes.Equal(plaintext, confirmation) {
				return caddy.ExitCodeFailedStartup, fmt.Errorf("password does not match")
			}
		} else {
			rd := bufio.NewReader(os.Stdin)
			plaintext, err = rd.ReadBytes('\n')
			if err != nil {
				return caddy.ExitCodeFailedStartup, err
			}

			plaintext = plaintext[:len(plaintext)-1] // Trailing newline
		}

		if len(plaintext) == 0 {
			return caddy.ExitCodeFailedStartup, fmt.Errorf("plaintext is required")
		}
	}

	var hash []byte
	switch algorithm {
	case "bcrypt":
		hash, err = BcryptHash{}.Hash(plaintext, nil)
	case "scrypt":
		def := ScryptHash{}
		def.SetDefaults()
		hash, err = def.Hash(plaintext, salt)
	default:
		return caddy.ExitCodeFailedStartup, fmt.Errorf("unrecognized hash algorithm: %s", algorithm)
	}
	if err != nil {
		return caddy.ExitCodeFailedStartup, err
	}

	hashBase64 := base64.StdEncoding.EncodeToString(hash)

	fmt.Println(hashBase64)

	return 0, nil
}
<commit_msg>caddyauth: Use buffered channel passed to signal.Notify (#3895)<commit_after>// Copyright 2015 Matthew Holt and The Caddy 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 caddyauth

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"flag"
	"fmt"
	"os"
	"os/signal"

	"github.com/caddyserver/caddy/v2"
	caddycmd "github.com/caddyserver/caddy/v2/cmd"
	"golang.org/x/crypto/ssh/terminal"
)

func init() {
	caddycmd.RegisterCommand(caddycmd.Command{
		Name:  "hash-password",
		Func:  cmdHashPassword,
		Usage: "[--algorithm <name>] [--salt <string>] [--plaintext <password>]",
		Short: "Hashes a password and writes base64",
		Long: `
Convenient way to hash a plaintext password. The resulting
hash is written to stdout as a base64 string.

--plaintext, when omitted, will be read from stdin. If
Caddy is attached to a controlling tty, the plaintext will
not be echoed.

--algorithm may be bcrypt or scrypt. If script, the default
parameters are used.

Use the --salt flag for algorithms which require a salt to
be provided (scrypt).
`,
		Flags: func() *flag.FlagSet {
			fs := flag.NewFlagSet("hash-password", flag.ExitOnError)
			fs.String("algorithm", "bcrypt", "Name of the hash algorithm")
			fs.String("plaintext", "", "The plaintext password")
			fs.String("salt", "", "The password salt")
			return fs
		}(),
	})
}

func cmdHashPassword(fs caddycmd.Flags) (int, error) {
	var err error

	algorithm := fs.String("algorithm")
	plaintext := []byte(fs.String("plaintext"))
	salt := []byte(fs.String("salt"))

	if len(plaintext) == 0 {
		fd := int(os.Stdin.Fd())
		if terminal.IsTerminal(fd) {
			// ensure the terminal state is restored on SIGINT
			state, _ := terminal.GetState(fd)
			c := make(chan os.Signal, 1)
			signal.Notify(c, os.Interrupt)
			go func() {
				<-c
				_ = terminal.Restore(fd, state)
				os.Exit(caddy.ExitCodeFailedStartup)
			}()
			defer signal.Stop(c)

			fmt.Fprint(os.Stderr, "Enter password: ")
			plaintext, err = terminal.ReadPassword(fd)
			fmt.Fprintln(os.Stderr)
			if err != nil {
				return caddy.ExitCodeFailedStartup, err
			}

			fmt.Fprint(os.Stderr, "Confirm password: ")
			confirmation, err := terminal.ReadPassword(fd)
			fmt.Fprintln(os.Stderr)
			if err != nil {
				return caddy.ExitCodeFailedStartup, err
			}

			if !bytes.Equal(plaintext, confirmation) {
				return caddy.ExitCodeFailedStartup, fmt.Errorf("password does not match")
			}
		} else {
			rd := bufio.NewReader(os.Stdin)
			plaintext, err = rd.ReadBytes('\n')
			if err != nil {
				return caddy.ExitCodeFailedStartup, err
			}

			plaintext = plaintext[:len(plaintext)-1] // Trailing newline
		}

		if len(plaintext) == 0 {
			return caddy.ExitCodeFailedStartup, fmt.Errorf("plaintext is required")
		}
	}

	var hash []byte
	switch algorithm {
	case "bcrypt":
		hash, err = BcryptHash{}.Hash(plaintext, nil)
	case "scrypt":
		def := ScryptHash{}
		def.SetDefaults()
		hash, err = def.Hash(plaintext, salt)
	default:
		return caddy.ExitCodeFailedStartup, fmt.Errorf("unrecognized hash algorithm: %s", algorithm)
	}
	if err != nil {
		return caddy.ExitCodeFailedStartup, err
	}

	hashBase64 := base64.StdEncoding.EncodeToString(hash)

	fmt.Println(hashBase64)

	return 0, nil
}
<|endoftext|>


<commit_before>package slack

import (
	"bytes"
	"log"
	"strconv"

	"github.com/dustin/go-humanize"
	"github.com/eveopsec/zk2s/zk2s/config"
	"github.com/eveopsec/zk2s/zk2s/filter"
	"github.com/eveopsec/zk2s/zk2s/tmpl"
	slacklib "github.com/nlopes/slack"
	"github.com/vivace-io/evelib/crest"
	"github.com/vivace-io/evelib/zkill"
)

// data is passed to templates for defining how a slacklib post appears.
type data struct {
	Killmail       crest.Killmail
	TotalValue     string
	IsLoss         bool
	IsSolo         bool
	InAlli         bool
	LosingCorp     string
	LosingAlli     string
	CorpsInvolved  []string
	AlliInvolved   []string
	PilotInvolved  []string
	FinalBlowPilot []string
	FinalBlowCorp  []string
	FinalBlowAlli  []string
	TotalCorp      []string
	TotalAlli      []string
}

// format loads the formatting template and applies formatting
// rules from the Configuration object.
func format(kill zkill.Kill, channel config.Channel) (messageParams slacklib.PostMessageParameters) {
	title := new(bytes.Buffer)
	body := new(bytes.Buffer)
	var err error

	// define post data for templates
	d := new(data)
	d.Killmail = kill.Killmail
	d.TotalValue = humanize.Comma(int64(kill.Zkb.TotalValue))
	d.IsLoss = filter.IsLoss(kill, channel)
	//Solo kill testing
	if len(kill.Killmail.Attackers) == 1 {
		d.IsSolo = true
	} else {
		d.IsLoss = false
	}
	//Testing to see if the victim is in an alliance

	if kill.Killmail.Victim.Alliance.Name != "" {
		d.InAlli = true
		d.LosingAlli = kill.Killmail.Victim.Alliance.Name
	}
	d.LosingCorp = kill.Killmail.Victim.Corporation.Name

	// Compile list of pilots involved, if not final blow
	for a := range kill.Killmail.Attackers {
		okToAdd := true
		if kill.Killmail.Attackers[a].FinalBlow == true {
			okToAdd = false
		}
		if kill.Killmail.Attackers[a].Character.Name == "" {
			okToAdd = false
		}
		if okToAdd {
			d.PilotInvolved = append(d.PilotInvolved, kill.Killmail.Attackers[a].Character.Name)
		}
	}

	//Compile the list for the final blow pilot, mainly use for formatting commas on the post
	for a := range kill.Killmail.Attackers {
		if kill.Killmail.Attackers[a].FinalBlow == true {
			okToAdd := true
			if kill.Killmail.Attackers[a].Character.Name == "" {
				okToAdd = false
			}
			if okToAdd {
				d.FinalBlowPilot = append(d.FinalBlowPilot, kill.Killmail.Attackers[a].Character.Name)
				d.FinalBlowCorp = append(d.FinalBlowCorp, kill.Killmail.Attackers[a].Corporation.Name)
				d.FinalBlowAlli = append(d.FinalBlowAlli, kill.Killmail.Attackers[a].Alliance.Name)
				d.TotalCorp = append(d.TotalCorp, kill.Killmail.Attackers[a].Corporation.Name)
				d.TotalAlli = append(d.TotalAlli, kill.Killmail.Attackers[a].Alliance.Name)
			}

		}
	}
	// Compile list of corporations involved from attackers, ignoring duplicates
	for a := range kill.Killmail.Attackers {
		okToAdd := true
		for c := range d.CorpsInvolved {
			if kill.Killmail.Attackers[a].Corporation.Name == d.CorpsInvolved[c] {
				okToAdd = false
				break
			}
			if kill.Killmail.Attackers[a].Corporation.Name == d.FinalBlowCorp[c] {
				okToAdd = false
				break
			}
			if okToAdd {
				d.CorpsInvolved = append(d.CorpsInvolved, kill.Killmail.Attackers[a].Corporation.Name)
				d.TotalCorp = append(d.TotalCorp, kill.Killmail.Attackers[a].Corporation.Name)
			}
		}
	}
	// Compile list of alliances involved from attackers, ignoring duplicates
	for a := range kill.Killmail.Attackers {

		okToAdd := true

		for c := range d.AlliInvolved {

			// Do not add blank alliances (corp is not in an alliance)
			if kill.Killmail.Attackers[a].Alliance.Name == "" {
				okToAdd = false
				break
			}
			if kill.Killmail.Attackers[a].Alliance.Name == d.AlliInvolved[c] {
				okToAdd = false
				d.InAlli = true
				break
			}
			if kill.Killmail.Attackers[a].Alliance.Name == d.FinalBlowAlli[c] {
				okToAdd = false
				d.InAlli = true
				break
			}
			if okToAdd {
				d.AlliInvolved = append(d.AlliInvolved, kill.Killmail.Attackers[a].Alliance.Name)
				d.TotalAlli = append(d.TotalAlli, kill.Killmail.Attackers[a].Alliance.Name)
				d.InAlli = true
			}
		}
	}

	// Execute templates
	err = tmpl.T.ExecuteTemplate(title, "kill-title", d)
	if err != nil {
		log.Println(err)
	}
	err = tmpl.T.ExecuteTemplate(body, "kill-body", d)
	if err != nil {
		log.Println(err)
	}

	attch := slacklib.Attachment{}
	attch.MarkdownIn = []string{"pretext", "text"}
	attch.Title = title.String()
	attch.TitleLink = "https://zkillboard.com/kill/" + strconv.Itoa(kill.KillID) + "/"
	attch.ThumbURL = "http://image.eveonline.com/render/" + strconv.Itoa(kill.Killmail.Victim.ShipType.ID) + "_64.png"
	attch.Text = body.String()
	//Color Coding
	if filter.IsLoss(kill, channel) {
		attch.Color = "danger"
	} else {
		attch.Color = "good"
	}
	messageParams.Attachments = []slacklib.Attachment{attch}
	messageParams.AsUser = true
	return
}
<commit_msg>fixed for changes in evelib dependencies<commit_after>package slack

import (
	"bytes"
	"log"
	"strconv"

	"github.com/dustin/go-humanize"
	"github.com/eveopsec/zk2s/zk2s/config"
	"github.com/eveopsec/zk2s/zk2s/filter"
	"github.com/eveopsec/zk2s/zk2s/tmpl"
	slacklib "github.com/nlopes/slack"
	"github.com/vivace-io/evelib/crest"
	"github.com/vivace-io/evelib/zkill"
)

// data is passed to templates for defining how a slacklib post appears.
type data struct {
	Killmail       crest.Killmail
	TotalValue     string
	IsLoss         bool
	IsSolo         bool
	InAlli         bool
	LosingCorp     string
	LosingAlli     string
	CorpsInvolved  []string
	AlliInvolved   []string
	PilotInvolved  []string
	FinalBlowPilot []string
	FinalBlowCorp  []string
	FinalBlowAlli  []string
	TotalCorp      []string
	TotalAlli      []string
}

// format loads the formatting template and applies formatting
// rules from the Configuration object.
func format(kill zkill.Kill, channel config.Channel) (messageParams slacklib.PostMessageParameters) {
	title := new(bytes.Buffer)
	body := new(bytes.Buffer)
	var err error

	// define post data for templates
	d := new(data)
	d.Killmail = *kill.Killmail
	d.TotalValue = humanize.Comma(int64(kill.Zkb.TotalValue))
	d.IsLoss = filter.IsLoss(kill, channel)
	//Solo kill testing
	if len(kill.Killmail.Attackers) == 1 {
		d.IsSolo = true
	} else {
		d.IsLoss = false
	}

	//Testing to see if the victim is in an alliance
	if kill.Killmail.Victim.Alliance.Name != "" {
		d.InAlli = true
		d.LosingAlli = kill.Killmail.Victim.Alliance.Name
	}
	d.LosingCorp = kill.Killmail.Victim.Corporation.Name

	// Compile list of pilots involved, if not final blow
	for a := range kill.Killmail.Attackers {
		okToAdd := true
		if kill.Killmail.Attackers[a].FinalBlow == true {
			okToAdd = false
		}
		if kill.Killmail.Attackers[a].Character.Name == "" {
			okToAdd = false
		}
		if okToAdd {
			d.PilotInvolved = append(d.PilotInvolved, kill.Killmail.Attackers[a].Character.Name)
		}
	}

	//Compile the list for the final blow pilot, mainly use for formatting commas on the post
	for a := range kill.Killmail.Attackers {
		if kill.Killmail.Attackers[a].FinalBlow == true {
			okToAdd := true
			if kill.Killmail.Attackers[a].Character.Name == "" {
				okToAdd = false
			}
			if okToAdd {
				d.FinalBlowPilot = append(d.FinalBlowPilot, kill.Killmail.Attackers[a].Character.Name)
				d.FinalBlowCorp = append(d.FinalBlowCorp, kill.Killmail.Attackers[a].Corporation.Name)
				d.FinalBlowAlli = append(d.FinalBlowAlli, kill.Killmail.Attackers[a].Alliance.Name)
				d.TotalCorp = append(d.TotalCorp, kill.Killmail.Attackers[a].Corporation.Name)
				d.TotalAlli = append(d.TotalAlli, kill.Killmail.Attackers[a].Alliance.Name)
			}

		}
	}
	// Compile list of corporations involved from attackers, ignoring duplicates
	for a := range kill.Killmail.Attackers {
		okToAdd := true
		for c := range d.CorpsInvolved {
			if kill.Killmail.Attackers[a].Corporation.Name == d.CorpsInvolved[c] {
				okToAdd = false
				break
			}
			if kill.Killmail.Attackers[a].Corporation.Name == d.FinalBlowCorp[c] {
				okToAdd = false
				break
			}
			if okToAdd {
				d.CorpsInvolved = append(d.CorpsInvolved, kill.Killmail.Attackers[a].Corporation.Name)
				d.TotalCorp = append(d.TotalCorp, kill.Killmail.Attackers[a].Corporation.Name)
			}
		}
	}
	// Compile list of alliances involved from attackers, ignoring duplicates
	for a := range kill.Killmail.Attackers {

		okToAdd := true

		for c := range d.AlliInvolved {

			// Do not add blank alliances (corp is not in an alliance)
			if kill.Killmail.Attackers[a].Alliance.Name == "" {
				okToAdd = false
				break
			}
			if kill.Killmail.Attackers[a].Alliance.Name == d.AlliInvolved[c] {
				okToAdd = false
				d.InAlli = true
				break
			}
			if kill.Killmail.Attackers[a].Alliance.Name == d.FinalBlowAlli[c] {
				okToAdd = false
				d.InAlli = true
				break
			}
			if okToAdd {
				d.AlliInvolved = append(d.AlliInvolved, kill.Killmail.Attackers[a].Alliance.Name)
				d.TotalAlli = append(d.TotalAlli, kill.Killmail.Attackers[a].Alliance.Name)
				d.InAlli = true
			}
		}
	}

	// Execute templates
	err = tmpl.T.ExecuteTemplate(title, "kill-title", d)
	if err != nil {
		log.Println(err)
	}
	err = tmpl.T.ExecuteTemplate(body, "kill-body", d)
	if err != nil {
		log.Println(err)
	}

	attch := slacklib.Attachment{}
	attch.MarkdownIn = []string{"pretext", "text"}
	attch.Title = title.String()
	attch.TitleLink = "https://zkillboard.com/kill/" + strconv.Itoa(kill.KillID) + "/"
	attch.ThumbURL = "http://image.eveonline.com/render/" + strconv.Itoa(kill.Killmail.Victim.ShipType.ID) + "_64.png"
	attch.Text = body.String()
	//Color Coding
	if filter.IsLoss(kill, channel) {
		attch.Color = "danger"
	} else {
		attch.Color = "good"
	}
	messageParams.Attachments = []slacklib.Attachment{attch}
	messageParams.AsUser = true
	return
}
<|endoftext|>