<commit_before>package main

import (
	"fmt"
	"errors"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type EmployeeList struct {
	NumberList []string
}
type CustomerList struct {
	NumberList []string
}
type ProjectList struct {
	NumberList []string
}
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte,error) {
    fmt.Println("Init is running " + function)
    var array []string
	list1 := EmployeeList{NumberList:array}
	list2 := CustomerList{NumberList:array}
	list3 := ProjectList{NumberList:array}

	employeeListMarshal, err := json.Marshal(list1)
	if err != nil {
		return nil,err
	}
	err = stub.PutState("WiproEmployees", employeeListMarshal)
	if err != nil {
		return nil,err
	}

	customerListMarshal, err := json.Marshal(list2)
	if err != nil {
		return nil,err
	}
	err = stub.PutState("WiproCustomers", customerListMarshal)
	if err != nil {
		return nil,err
	}

	projectListMarshal, err := json.Marshal(list3)
	if err != nil {
		return nil,err
	}
	err = stub.PutState("WiproProjects", projectListMarshal)
	if err != nil {
		return nil,err
	}
    return nil,nil
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface , function string, args []string) ([]byte,error){
	fmt.Println("Invoke is running "+function)
	if function =="initEmployee"{
		return t.initEmployee(stub,args)
	}else if function == "initCustomer"{
		return t.initCustomer(stub,args)
	}

	return nil,errors.New("Received unknown function invoke")
}

func (t *SimpleChaincode) initEmployee(stub shim.ChaincodeStubInterface, args []string) ([]byte,error){
	if len(args)!=1{
		return nil,errors.New("Incorrect number of arguments. Expecting 1")
	}
	employeeListMarshal, err := stub.GetState("WiproEmployees")
	if err != nil {
		return nil,err
	}
	var e EmployeeList
	json.Unmarshal(employeeListMarshal,&e)
	e.NumberList = append(e.NumberList,args[0])

	employeeListMarshal, err = json.Marshal(e)
	if err!=nil{
		return nil,err
	}

	err = stub.PutState("WiproEmployees", employeeListMarshal)
	if err!=nil{
		return nil,err
	}
	return nil,nil
}

func (t *SimpleChaincode) initCustomer(stub shim.ChaincodeStubInterface, args []string) ([]byte,error){
	if len(args)!=1{
		return nil,errors.New("Incorrect number of arguments. Expecting 1")
	}
	customerListMarshal, err := stub.GetState("WiproCustomers")
	if err != nil {
		return nil,err
	}
	var c CustomerList
	json.Unmarshal(customerListMarshal,&c)
	c.NumberList = append(c.NumberList,args[0])

	customerListMarshal, err = json.Marshal(c)
	if err!=nil{
		return nil,err
	}

	err = stub.PutState("WiproCustomers", customerListMarshal)
	if err!=nil{
		return nil,err
	}
	return nil,nil
}
func (t *SimpleChaincode) initProject(stub shim.ChaincodeStubInterface, args []string) ([]byte,error){
	if len(args)!=1{
		return nil,errors.New("Incorrect number of arguments. Expecting 1")
	}
	projectListMarshal, err := stub.GetState("WiproProjects")
	if err != nil {
		return nil,err
	}
	var p ProjectList
	json.Unmarshal(projectListMarshal,&p)
	p.NumberList = append(p.NumberList,args[0])

	projectListMarshal, err = json.Marshal(p)
	if err!=nil{
		return nil,err
	}

	err = stub.PutState("WiproProjects", projectListMarshal)
	if err!=nil{
		return nil,err
	}
	return nil,nil
}

func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface , function string, args []string) ([]byte,error){
	fmt.Println("Query is running "+function)
	if function=="allEmployees"{
		return t.allEmployees(stub,args)
	}else if function=="allCustomers"{
		return t.allCustomers(stub,args)
	}else if function=="allProjects"{
		return t.allProjects(stub,args)
	}
	return nil,errors.New("Received unknown function query "+function)
}
func (t *SimpleChaincode) allCustomers(stub shim.ChaincodeStubInterface, args []string)([]byte, error){
	if len(args)!=0{
		return nil,errors.New("Received incorrect number of arguments. Expected 0")
	}
	customerListMarshal, err := stub.GetState("WiproCustomers")
	if err != nil {
		return nil,err
	}
	return customerListMarshal,nil
}
func (t *SimpleChaincode) allProjects(stub shim.ChaincodeStubInterface, args []string)([]byte, error){
	if len(args)!=0{
		return nil,errors.New("Received incorrect number of arguments. Expected 0")
	}
	projectsListMarshal, err := stub.GetState("WiproProjects")
	if err != nil {
		return nil,err
	}
	return projectsListMarshal,nil
}
func (t *SimpleChaincode) allEmployees(stub shim.ChaincodeStubInterface, args []string)([]byte, error){
	if len(args)!=0{
		return nil,errors.New("Received incorrect number of arguments. Expected 0")
	}
	employeeListMarshal, err := stub.GetState("WiproEmployees")
	if err != nil {
		return nil,err
	}
	return employeeListMarshal,nil
}
func main() {
    	err := shim.Start(new(SimpleChaincode))
    if err != nil {
        fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}
<commit_msg>added return values to some functions<commit_after>package main

import (
	"fmt"
	"errors"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type EmployeeList struct {
	NumberList []string
}
type CustomerList struct {
	NumberList []string
}
type ProjectList struct {
	NumberList []string
}
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte,error) {
    fmt.Println("Init is running " + function)
    var array []string
	list1 := EmployeeList{NumberList:array}
	list2 := CustomerList{NumberList:array}
	list3 := ProjectList{NumberList:array}

	employeeListMarshal, err := json.Marshal(list1)
	if err != nil {
		return nil,err
	}
	err = stub.PutState("WiproEmployees", employeeListMarshal)
	if err != nil {
		return nil,err
	}

	customerListMarshal, err := json.Marshal(list2)
	if err != nil {
		return nil,err
	}
	err = stub.PutState("WiproCustomers", customerListMarshal)
	if err != nil {
		return nil,err
	}

	projectListMarshal, err := json.Marshal(list3)
	if err != nil {
		return nil,err
	}
	err = stub.PutState("WiproProjects", projectListMarshal)
	if err != nil {
		return nil,err
	}
    return nil,nil
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface , function string, args []string) ([]byte,error){
	fmt.Println("Invoke is running "+function)
	if function =="initEmployee"{
		return t.initEmployee(stub,args)
	}else if function == "initCustomer"{
		return t.initCustomer(stub,args)
	}else if function == "initProject"{
		return t.initProject(stub,args)
	}

	return nil,errors.New("Received unknown function invoke")
}

func (t *SimpleChaincode) initEmployee(stub shim.ChaincodeStubInterface, args []string) ([]byte,error){
	if len(args)!=1{
		return nil,errors.New("Incorrect number of arguments. Expecting 1")
	}
	employeeListMarshal, err := stub.GetState("WiproEmployees")
	if err != nil {
		return nil,err
	}
	var e EmployeeList
	json.Unmarshal(employeeListMarshal,&e)
	e.NumberList = append(e.NumberList,args[0])

	employeeListMarshal, err = json.Marshal(e)
	if err!=nil{
		return nil,err
	}

	err = stub.PutState("WiproEmployees", employeeListMarshal)
	if err!=nil{
		return nil,err
	}
	return nil,nil
}

func (t *SimpleChaincode) initCustomer(stub shim.ChaincodeStubInterface, args []string) ([]byte,error){
	if len(args)!=1{
		return nil,errors.New("Incorrect number of arguments. Expecting 1")
	}
	customerListMarshal, err := stub.GetState("WiproCustomers")
	if err != nil {
		return nil,err
	}
	var c CustomerList
	json.Unmarshal(customerListMarshal,&c)
	c.NumberList = append(c.NumberList,args[0])

	customerListMarshal, err = json.Marshal(c)
	if err!=nil{
		return nil,err
	}

	err = stub.PutState("WiproCustomers", customerListMarshal)
	if err!=nil{
		return nil,err
	}
	return nil,nil
}
func (t *SimpleChaincode) initProject(stub shim.ChaincodeStubInterface, args []string) ([]byte,error){
	if len(args)!=1{
		return nil,errors.New("Incorrect number of arguments. Expecting 1")
	}
	projectListMarshal, err := stub.GetState("WiproProjects")
	if err != nil {
		return nil,err
	}
	var p ProjectList
	json.Unmarshal(projectListMarshal,&p)
	p.NumberList = append(p.NumberList,args[0])

	projectListMarshal, err = json.Marshal(p)
	if err!=nil{
		return nil,err
	}

	err = stub.PutState("WiproProjects", projectListMarshal)
	if err!=nil{
		return nil,err
	}
	return nil,nil
}

func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface , function string, args []string) ([]byte,error){
	fmt.Println("Query is running "+function)
	if function=="allEmployees"{
		return t.allEmployees(stub,args)
	}else if function=="allCustomers"{
		return t.allCustomers(stub,args)
	}else if function=="allProjects"{
		return t.allProjects(stub,args)
	}
	return nil,errors.New("Received unknown function query "+function)
}
func (t *SimpleChaincode) allCustomers(stub shim.ChaincodeStubInterface, args []string)([]byte, error){
	if len(args)!=0{
		return nil,errors.New("Received incorrect number of arguments. Expected 0")
	}
	customerListMarshal, err := stub.GetState("WiproCustomers")
	if err != nil {
		return nil,err
	}
	return customerListMarshal,nil
}
func (t *SimpleChaincode) allProjects(stub shim.ChaincodeStubInterface, args []string)([]byte, error){
	if len(args)!=0{
		return nil,errors.New("Received incorrect number of arguments. Expected 0")
	}
	projectsListMarshal, err := stub.GetState("WiproProjects")
	if err != nil {
		return nil,err
	}
	return projectsListMarshal,nil
}
func (t *SimpleChaincode) allEmployees(stub shim.ChaincodeStubInterface, args []string)([]byte, error){
	if len(args)!=0{
		return nil,errors.New("Received incorrect number of arguments. Expected 0")
	}
	employeeListMarshal, err := stub.GetState("WiproEmployees")
	if err != nil {
		return nil,err
	}
	return employeeListMarshal,nil
}
func main() {
    	err := shim.Start(new(SimpleChaincode))
    if err != nil {
        fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}
<|endoftext|>


<commit_before>package dice

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

// Dice represents a set of 1 type of dice, i.e: 3d20 OR 2d4 OR 1d6
// Types are not mixed as it is unnecessary
type Dice struct {
	Number, Sides int
	r             *rand.Rand
}

// NewDice returns a new Dice collection where
func NewDice(number, sides int) *Dice {
	return &Dice{number, sides, rand.New(rand.NewSource(time.Now().UnixNano()))}
}

// Roll all dice in set and return the aggregate result
func (d *Dice) Roll() int {
	t := 0
	for i := 0; i < d.Number; i++ {
		t += d.r.Intn(d.Sides) + 1
	}
	return t
}

// String satisfies the Stringer interface for Dice
func (d *Dice) String() string {
	return fmt.Sprintf("%dd%d", d.Number, d.Sides)
}

// Bag is a collection of different types of Dice, i.e: 3d20 AND 2d4 AND 1d6
type Bag []*Dice

// NewBag returns a new Bag object
func NewBag() Bag {
	return Bag{}
}

// Add puts more dice in the bag
func (b Bag) Add(d *Dice) {
	b = append(b, d)
}

// Roll returns aggregate rolls of all dice in the bag
func (b Bag) Roll() int {
	t := 0

	for _, d := range b {
		t += d.Roll()
	}

	return t
}

// String satisfies the Stringer interface for Bags
func (b Bag) String() string {
	v := make([]string, len(b))

	for i, d := range b {
		v[i] = fmt.Sprint(d)
	}

	return strings.Join(v, ", ")
}
<commit_msg>tidied comments<commit_after>package dice

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

// Dice represents a set of 1 type of dice, i.e: 3d20 OR 2d4 OR 1d6
type Dice struct {
	Number, Sides int
	r             *rand.Rand
}

// NewDice returns a new Dice set
func NewDice(number, sides int) *Dice {
	return &Dice{number, sides, rand.New(rand.NewSource(time.Now().UnixNano()))}
}

// Roll all dice in set and return the aggregate result
func (d *Dice) Roll() int {
	t := 0
	for i := 0; i < d.Number; i++ {
		t += d.r.Intn(d.Sides) + 1
	}
	return t
}

// String satisfies the Stringer interface for Dice
func (d *Dice) String() string {
	return fmt.Sprintf("%dd%d", d.Number, d.Sides)
}

// Bag is a collection of different types of Dice, i.e: 3d20, 2d4, 1d6
type Bag []*Dice

// NewBag returns a new Bag object
func NewBag() Bag {
	return Bag{}
}

// Add puts more dice in the bag
func (b Bag) Add(d *Dice) {
	b = append(b, d)
}

// Roll returns aggregate rolls of all Dice in the bag
func (b Bag) Roll() int {
	t := 0

	for _, d := range b {
		t += d.Roll()
	}

	return t
}

// String satisfies the Stringer interface for Bags
func (b Bag) String() string {
	v := make([]string, len(b))

	for i, d := range b {
		v[i] = fmt.Sprint(d)
	}

	return strings.Join(v, ", ")
}
<|endoftext|>


<commit_before>package diff

import (
	"bytes"
	"fmt"
	"io"
)

// A Diffable type can be diffed using Myers.
// A is the initial state; B is the final state.
type Diffable interface {
	LenA() int
	LenB() int
	Equal(ai, bi int) bool
}

// A Writeable type can be written using WriteUnified.
// A is the initial state; B is the final state.
type Writeable interface {
	// WriteATo writes the element a[idx] to w.
	WriteATo(w io.Writer, idx int) (int, error)
	// WriteBTo writes the element b[idx] to w.
	WriteBTo(w io.Writer, idx int) (int, error)
	// NameA returns the name to use for a, commonly a filename.
	NameA() string
	// NameB returns the name to use for b, commonly a filename.
	NameB() string
}

// DiffableWriteable is the union of Diffable and Writeable.
// TODO: better name
type DiffableWriteable interface {
	Diffable
	Writeable
}

// TODO: consider adding a StringIntern type, something like:
//
// type StringIntern struct {
// 	s map[string]*string
// }
//
// func (i *StringIntern) Bytes(b []byte) *string
// func (i *StringIntern) String(s string) *string
//
// And document what it is and why to use it.
// And consider adding helper functions to Strings and Bytes to use it.
// The reason to use it is that a lot of the execution time in diffing
// (which is an expensive operation) is taken up doing string comparisons.
// If you have paid the O(n) cost to intern all strings involved in both A and B,
// then string comparisons are reduced to cheap pointer comparisons.

// An op is a edit operation used to transform A into B.
type op int8

//go:generate stringer -type op

const (
	del op = -1
	eq  op = 0
	ins op = 1
)

// A segment is a set of steps of the same op.
type segment struct {
	FromA, ToA int // Beginning and ending indices into A of this operation
	FromB, ToB int // ditto, for B
}

func (s segment) op() op {
	if s.FromA == s.ToA {
		return ins
	}
	if s.FromB == s.ToB {
		return del
	}
	return eq
}

func (s segment) String() string {
	// This output is helpful when hacking on a Myers diff.
	// In other contexts it is usually more natural to group FromA, ToA and FromB, ToB.
	return fmt.Sprintf("(%d, %d) -- %s %d --> (%d, %d)", s.FromA, s.FromB, s.op(), s.Len(), s.ToA, s.ToB)
}

func (s segment) Len() int {
	if s.FromA == s.ToA {
		return s.ToB - s.FromB
	}
	return s.ToA - s.FromA
}

// An EditScript is an edit script to alter A into B.
type EditScript struct {
	segs []segment
}

// IsIdentity reports whether e is the identity edit script, that is, whether A and B are identical.
// See the TestHelper example.
func (e EditScript) IsIdentity() bool {
	for _, seg := range e.segs {
		if seg.op() != eq {
			return false
		}
	}
	return true
}

// TODO: consider adding an "it just works" test helper that accepts two slices (via interface{}),
// diffs them using Strings or Bytes or Slices (using reflect.DeepEqual) as appropriate,
// and calls t.Errorf with a generated diff if they're not equal.

// scriptWithSegments returns an EditScript containing s.
// It is used to reduce line noise.
func scriptWithSegments(s ...segment) EditScript {
	return EditScript{segs: s}
}

// dump formats s for debugging.
func (e EditScript) dump() string {
	buf := new(bytes.Buffer)
	for _, seg := range e.segs {
		fmt.Fprintln(buf, seg)
	}
	return buf.String()
}
<commit_msg>add docs to Diffable methods<commit_after>package diff

import (
	"bytes"
	"fmt"
	"io"
)

// A Diffable type can be diffed using Myers.
// A is the initial state; B is the final state.
type Diffable interface {
	// LenA returns the number of initial elements.
	LenA() int
	// LenA returns the number of final elements.
	LenB() int
	// Equal reports whether the ai'th element of A is equal to the bi'th element of B.
	Equal(ai, bi int) bool
}

// A Writeable type can be written using WriteUnified.
// A is the initial state; B is the final state.
type Writeable interface {
	// WriteATo writes the element a[idx] to w.
	WriteATo(w io.Writer, idx int) (int, error)
	// WriteBTo writes the element b[idx] to w.
	WriteBTo(w io.Writer, idx int) (int, error)
	// NameA returns the name to use for a, commonly a filename.
	NameA() string
	// NameB returns the name to use for b, commonly a filename.
	NameB() string
}

// DiffableWriteable is the union of Diffable and Writeable.
// TODO: better name
type DiffableWriteable interface {
	Diffable
	Writeable
}

// TODO: consider adding a StringIntern type, something like:
//
// type StringIntern struct {
// 	s map[string]*string
// }
//
// func (i *StringIntern) Bytes(b []byte) *string
// func (i *StringIntern) String(s string) *string
//
// And document what it is and why to use it.
// And consider adding helper functions to Strings and Bytes to use it.
// The reason to use it is that a lot of the execution time in diffing
// (which is an expensive operation) is taken up doing string comparisons.
// If you have paid the O(n) cost to intern all strings involved in both A and B,
// then string comparisons are reduced to cheap pointer comparisons.

// An op is a edit operation used to transform A into B.
type op int8

//go:generate stringer -type op

const (
	del op = -1
	eq  op = 0
	ins op = 1
)

// A segment is a set of steps of the same op.
type segment struct {
	FromA, ToA int // Beginning and ending indices into A of this operation
	FromB, ToB int // ditto, for B
}

func (s segment) op() op {
	if s.FromA == s.ToA {
		return ins
	}
	if s.FromB == s.ToB {
		return del
	}
	return eq
}

func (s segment) String() string {
	// This output is helpful when hacking on a Myers diff.
	// In other contexts it is usually more natural to group FromA, ToA and FromB, ToB.
	return fmt.Sprintf("(%d, %d) -- %s %d --> (%d, %d)", s.FromA, s.FromB, s.op(), s.Len(), s.ToA, s.ToB)
}

func (s segment) Len() int {
	if s.FromA == s.ToA {
		return s.ToB - s.FromB
	}
	return s.ToA - s.FromA
}

// An EditScript is an edit script to alter A into B.
type EditScript struct {
	segs []segment
}

// IsIdentity reports whether e is the identity edit script, that is, whether A and B are identical.
// See the TestHelper example.
func (e EditScript) IsIdentity() bool {
	for _, seg := range e.segs {
		if seg.op() != eq {
			return false
		}
	}
	return true
}

// TODO: consider adding an "it just works" test helper that accepts two slices (via interface{}),
// diffs them using Strings or Bytes or Slices (using reflect.DeepEqual) as appropriate,
// and calls t.Errorf with a generated diff if they're not equal.

// scriptWithSegments returns an EditScript containing s.
// It is used to reduce line noise.
func scriptWithSegments(s ...segment) EditScript {
	return EditScript{segs: s}
}

// dump formats s for debugging.
func (e EditScript) dump() string {
	buf := new(bytes.Buffer)
	for _, seg := range e.segs {
		fmt.Fprintln(buf, seg)
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package manifest_test

import (
	"cf/manifest"
	"generic"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"runtime"
	"strings"
	testassert "testhelpers/assert"
)

func testManifestWithAbsolutePathOnPosix() {
	m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
		"applications": []interface{}{
			map[interface{}]interface{}{
				"path": "/another/path-segment",
			},
		},
	}))

	Expect(errs).To(BeEmpty())
	Expect(*m.Applications[0].Path).To(Equal("/another/path-segment"))
}

func testManifestWithAbsolutePathOnWindows() {
	m, errs := manifest.NewManifest(`C:\some\path`, generic.NewMap(map[interface{}]interface{}{
		"applications": []interface{}{
			map[interface{}]interface{}{
				"path": `C:\another\path`,
			},
		},
	}))

	Expect(errs).To(BeEmpty())
	Expect(*m.Applications[0].Path).To(Equal(`C:\another\path`))
}

var _ = Describe("Testing with ginkgo", func() {
	It("TestManifestWithGlobalAndAppSpecificProperties", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"instances": "3",
			"memory":    "512M",
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name":     "bitcoin-miner",
					"no-route": true,
				},
			},
		}))

		Expect(errs).To(BeEmpty())

		apps := m.Applications
		Expect(*apps[0].InstanceCount).To(Equal(3))
		Expect(*apps[0].Memory).To(Equal(uint64(512)))
		Expect(*apps[0].NoRoute).To(BeTrue())
	})

	It("TestManifestWithInvalidMemory", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"instances": "3",
			"memory":    "512",
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name": "bitcoin-miner",
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		Expect(errs.Error()).To(ContainSubstring("memory"))
	})

	It("TestManifestWithTimeoutSetsHealthCheckTimeout", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name":    "bitcoin-miner",
					"timeout": "360",
				},
			},
		}))

		Expect(errs).To(BeEmpty())
		Expect(*m.Applications[0].HealthCheckTimeout).To(Equal(360))
	})

	It("TestManifestWithEmptyEnvVarIsInvalid", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"env": generic.NewMap(map[interface{}]interface{}{
				"bar": nil,
			}),
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name": "bad app",
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		Expect(errs.Error()).To(ContainSubstring("env var 'bar' should not be null"))
	})

	It("returns an empty map when no env was present in the manifest", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{"name": "no-env-vars"},
			},
		}))
		Expect(errs).To(BeEmpty())
		Expect(*m.Applications[0].EnvironmentVars).NotTo(BeNil())
	})

	It("TestManifestWithAbsolutePath", func() {
		if runtime.GOOS == "windows" {
			testManifestWithAbsolutePathOnWindows()
		} else {
			testManifestWithAbsolutePathOnPosix()
		}
	})

	It("TestManifestWithRelativePath", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"path": "../another/path-segment",
				},
			},
		}))

		Expect(errs).To(BeEmpty())
		if runtime.GOOS == "windows" {
			Expect(*m.Applications[0].Path).To(Equal("\\some\\another\\path-segment"))
		} else {
			Expect(*m.Applications[0].Path).To(Equal("/some/another/path-segment"))
		}
	})

	It("TestParsingManifestWithNulls", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"buildpack":  nil,
					"disk_quota": nil,
					"domain":     nil,
					"host":       nil,
					"name":       nil,
					"path":       nil,
					"stack":      nil,
					"memory":     nil,
					"instances":  nil,
					"timeout":    nil,
					"no-route":   nil,
					"services":   nil,
					"env":        nil,
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		errorSlice := strings.Split(errs.Error(), "\n")
		manifestKeys := []string{"buildpack", "disk_quota", "domain", "host", "name", "path", "stack",
			"memory", "instances", "timeout", "no-route", "services", "env"}

		for _, key := range manifestKeys {
			testassert.SliceContains(errorSlice, testassert.Lines{{key, "not be null"}})
		}
	})

	It("returns an error when the manifest contains old-style property syntax", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"env": map[interface{}]interface{}{
						"bar": "many-${some_property-name}-are-cool",
					},
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		Expect(errs.Error()).To(ContainSubstring("'${some_property-name}'"))
	})

	It("TestParsingManifestWithNullCommand", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"command": nil,
				},
			},
		}))

		Expect(errs).To(BeEmpty())
		Expect(*m.Applications[0].Command).To(Equal(""))
	})

	It("TestParsingEmptyManifestDoesNotSetCommand", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{},
			},
		}))

		Expect(errs).To(BeEmpty())
		Expect(m.Applications[0].Command).To(BeNil())
	})
})
<commit_msg>refactor manifest tests to ginkgo style<commit_after>package manifest_test

import (
	"cf/manifest"
	"generic"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"runtime"
	"strings"
	testassert "testhelpers/assert"
)

var _ = Describe("Manifests", func() {
	It("merges global properties into each app's properties", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"instances": "3",
			"memory":    "512M",
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name":     "bitcoin-miner",
					"no-route": true,
				},
			},
		}))

		Expect(errs).To(BeEmpty())

		apps := m.Applications
		Expect(*apps[0].InstanceCount).To(Equal(3))
		Expect(*apps[0].Memory).To(Equal(uint64(512)))
		Expect(*apps[0].NoRoute).To(BeTrue())
	})

	It("returns an error when the memory limit doesn't have a unit", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"instances": "3",
			"memory":    "512",
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name": "bitcoin-miner",
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		Expect(errs.Error()).To(ContainSubstring("memory"))
	})

	It("sets applications' health check timeouts", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name":    "bitcoin-miner",
					"timeout": "360",
				},
			},
		}))

		Expect(errs).To(BeEmpty())
		Expect(*m.Applications[0].HealthCheckTimeout).To(Equal(360))
	})

	It("does not allow nil values for environment variables", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"env": generic.NewMap(map[interface{}]interface{}{
				"bar": nil,
			}),
			"applications": []interface{}{
				map[interface{}]interface{}{
					"name": "bad app",
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		Expect(errs.Error()).To(ContainSubstring("env var 'bar' should not be null"))
	})

	It("returns an empty map when no env was present in the manifest", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{"name": "no-env-vars"},
			},
		}))
		Expect(errs).To(BeEmpty())
		Expect(*m.Applications[0].EnvironmentVars).NotTo(BeNil())
	})

	It("allows applications to have absolute paths", func() {
		if runtime.GOOS == "windows" {
			m, errs := manifest.NewManifest(`C:\some\path`, generic.NewMap(map[interface{}]interface{}{
				"applications": []interface{}{
					map[interface{}]interface{}{
						"path": `C:\another\path`,
					},
				},
			}))

			Expect(errs).To(BeEmpty())
			Expect(*m.Applications[0].Path).To(Equal(`C:\another\path`))
		} else {
			m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
				"applications": []interface{}{
					map[interface{}]interface{}{
						"path": "/another/path-segment",
					},
				},
			}))

			Expect(errs).To(BeEmpty())
			Expect(*m.Applications[0].Path).To(Equal("/another/path-segment"))
		}
	})

	It("expands relative app paths based on the manifest's path", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"path": "../another/path-segment",
				},
			},
		}))

		Expect(errs).To(BeEmpty())
		if runtime.GOOS == "windows" {
			Expect(*m.Applications[0].Path).To(Equal("\\some\\another\\path-segment"))
		} else {
			Expect(*m.Applications[0].Path).To(Equal("/some/another/path-segment"))
		}
	})

	It("returns errors when there are null values", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"buildpack":  nil,
					"disk_quota": nil,
					"domain":     nil,
					"host":       nil,
					"name":       nil,
					"path":       nil,
					"stack":      nil,
					"memory":     nil,
					"instances":  nil,
					"timeout":    nil,
					"no-route":   nil,
					"services":   nil,
					"env":        nil,
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		errorSlice := strings.Split(errs.Error(), "\n")
		manifestKeys := []string{"buildpack", "disk_quota", "domain", "host", "name", "path", "stack",
			"memory", "instances", "timeout", "no-route", "services", "env"}

		for _, key := range manifestKeys {
			testassert.SliceContains(errorSlice, testassert.Lines{{key, "not be null"}})
		}
	})

	It("returns an error when the manifest contains old-style property syntax", func() {
		_, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"env": map[interface{}]interface{}{
						"bar": "many-${some_property-name}-are-cool",
					},
				},
			},
		}))

		Expect(errs).NotTo(BeEmpty())
		Expect(errs.Error()).To(ContainSubstring("'${some_property-name}'"))
	})

	It("sets the command to blank when its value is null in the manifest", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{
					"command": nil,
				},
			},
		}))

		Expect(errs).To(BeEmpty())
		Expect(*m.Applications[0].Command).To(Equal(""))
	})

	It("does not set the start command when the manifest doesn't have the 'command' key", func() {
		m, errs := manifest.NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{
			"applications": []interface{}{
				map[interface{}]interface{}{},
			},
		}))

		Expect(errs).To(BeEmpty())
		Expect(m.Applications[0].Command).To(BeNil())
	})
})
<|endoftext|>


<commit_before>package bridge

import (
	"errors"
	"log"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"sync"

	dockerapi "github.com/fsouza/go-dockerclient"
)

var serviceIDPattern = regexp.MustCompile(`^(.+?):([a-zA-Z0-9][a-zA-Z0-9_.-]+):[0-9]+(?::udp)?$`)

type Bridge struct {
	sync.Mutex
	registry       RegistryAdapter
	docker         *dockerapi.Client
	services       map[string][]*Service
	deadContainers map[string]*DeadContainer
	config         Config
}

func New(docker *dockerapi.Client, adapterUri string, config Config) (*Bridge, error) {
	uri, err := url.Parse(adapterUri)
	if err != nil {
		return nil, errors.New("bad adapter uri: " + adapterUri)
	}
	factory, found := AdapterFactories.Lookup(uri.Scheme)
	if !found {
		return nil, errors.New("unrecognized adapter: " + adapterUri)
	}

	log.Println("Using", uri.Scheme, "adapter:", uri)
	return &Bridge{
		docker:         docker,
		config:         config,
		registry:       factory.New(uri),
		services:       make(map[string][]*Service),
		deadContainers: make(map[string]*DeadContainer),
	}, nil
}

func (b *Bridge) Ping() error {
	return b.registry.Ping()
}

func (b *Bridge) Add(containerId string) {
	b.add(containerId, false)
}

func (b *Bridge) Remove(containerId string) {
	b.remove(containerId, true)
}

func (b *Bridge) RemoveOnExit(containerId string) {
	b.remove(containerId, b.shouldRemove(containerId))
}

func (b *Bridge) Refresh() {
	for containerId, services := range b.getServicesCopy() {
		for _, service := range services {
			err := b.registry.Refresh(service)
			if err != nil {
				log.Println("refresh failed:", service.ID, err)
				continue
			}
			log.Println("refreshed:", containerId[:12], service.ID)
		}
	}
}

func (b *Bridge) PruneDeadContainers() {
	b.Lock()
	defer b.Unlock()
	for containerId, deadContainer := range b.deadContainers {
		deadContainer.TTL -= b.config.RefreshInterval
		if deadContainer.TTL <= 0 {
			delete(b.deadContainers, containerId)
		}
	}
}

// Get a deep copy of the current services in a thread-safe way
func (b *Bridge) getServicesCopy() map[string][]*Service {
	b.Lock()
	defer b.Unlock()
	svcsCopy := make(map[string][]*Service)

	for id, svc := range b.services {
		var svcPointers []*Service
		for _, s := range svc {
			t := *s
			z := &t
			svcPointers = append(svcPointers, z)
		}
		svcsCopy[id] = svcPointers
	}
	return svcsCopy
}

func (b *Bridge) Sync(quiet bool) {

	// Take this to avoid having to use a mutex
	servicesSnapshot := b.getServicesCopy()

	containers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{})
	if err != nil && quiet {
		log.Println("error listing containers, skipping sync")
		return
	} else if err != nil && !quiet {
		log.Fatal(err)
	}

	log.Printf("Syncing services on %d containers", len(containers))

	// NOTE: This assumes reregistering will do the right thing, i.e. nothing..
	for _, listing := range containers {
		services := servicesSnapshot[listing.ID]
		if services == nil {
			go b.add(listing.ID, quiet)
		} else {
			for _, service := range services {
				err := b.registry.Register(service)
				if err != nil {
					log.Println("sync register failed:", service, err)
				}
			}
		}
	}

	// Clean up services that were registered previously, but aren't
	// acknowledged within registrator
	if b.config.Cleanup {
		// Remove services if its corresponding container is not running
		log.Println("Listing non-exited containers")
		filters := map[string][]string{"status": {"created", "restarting", "running", "paused"}}
		nonExitedContainers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{Filters: filters})
		if err != nil {
			log.Println("error listing nonExitedContainers, skipping sync", err)
			return
		}
		for listingId, _ := range servicesSnapshot {
			found := false
			for _, container := range nonExitedContainers {
				if listingId == container.ID {
					found = true
					break
				}
			}
			// This is a container that does not exist
			if !found {
				log.Printf("stale: Removing service %s because it does not exist", listingId)
				go b.RemoveOnExit(listingId)
			}
		}

		log.Println("Cleaning up dangling services")
		extServices, err := b.registry.Services()
		if err != nil {
			log.Println("cleanup failed:", err)
			return
		}

	Outer:
		for _, extService := range extServices {
			matches := serviceIDPattern.FindStringSubmatch(extService.ID)
			if len(matches) != 3 {
				// There's no way this was registered by us, so leave it
				continue
			}
			serviceHostname := matches[1]
			if serviceHostname != Hostname {
				// ignore because registered on a different host
				continue
			}
			serviceContainerName := matches[2]
			for _, listing := range servicesSnapshot {
				for _, service := range listing {
					if service.Name == extService.Name && serviceContainerName == service.Origin.container.Name[1:] {
						continue Outer
					}
				}
			}
			log.Println("dangling:", extService.ID)
			err := b.registry.Deregister(extService)
			if err != nil {
				log.Println("deregister failed:", extService.ID, err)
				continue
			}
			log.Println(extService.ID, "removed")
		}
	}
}

func (b *Bridge) deleteDeadContainer(containerId string) {
	b.Lock()
	defer b.Unlock()

	if d := b.deadContainers[containerId]; d != nil {
		b.services[containerId] = d.Services
		delete(b.deadContainers, containerId)
	}
}

func (b *Bridge) appendService(containerId string, service *Service) {
	b.services[containerId] = append(b.services[containerId], service)
	log.Println("added:", containerId[:12], service.ID)
}

func (b *Bridge) add(containerId string, quiet bool) {
	b.deleteDeadContainer(containerId)

	b.Lock()
	defer b.Unlock()

	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, ignoring")
		// Alternatively, remove and readd or resubmit.
		return
	}

	container, err := b.docker.InspectContainer(containerId)
	if err != nil {
		log.Println("unable to inspect container:", containerId[:12], err)
		return
	}

	ports := make(map[string]ServicePort)

	// Extract configured host port mappings, relevant when using --net=host
	for port, _ := range container.Config.ExposedPorts {
		published := []dockerapi.PortBinding{{"0.0.0.0", port.Port()}}
		ports[string(port)] = servicePort(container, port, published)
	}

	// Extract runtime port mappings, relevant when using --net=bridge
	for port, published := range container.NetworkSettings.Ports {
		ports[string(port)] = servicePort(container, port, published)
	}

	if len(ports) == 0 && !quiet {
		log.Println("ignored:", container.ID[:12], "no published ports")
		return
	}

	servicePorts := make(map[string]ServicePort)
	for key, port := range ports {
		if b.config.Internal != true && port.HostPort == "" {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "port", port.ExposedPort, "not published on host")
			}
			continue
		}
		servicePorts[key] = port
	}

	isGroup := len(servicePorts) > 1
	for _, port := range servicePorts {
		service := b.newService(port, isGroup)
		if service == nil {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "service on port", port.ExposedPort)
			}
			continue
		}
		err := b.registry.Register(service)
		if err != nil {
			log.Println("register failed:", service, err)
			continue
		}
		b.appendService(container.ID, service)
	}
}

func (b *Bridge) newService(port ServicePort, isgroup bool) *Service {
	container := port.container
	defaultName := strings.Split(path.Base(container.Config.Image), ":")[0]

	// not sure about this logic. kind of want to remove it.
	hostname := Hostname
	if hostname == "" {
		hostname = port.HostIP
	}
	if port.HostIP == "0.0.0.0" {
		ip, err := net.ResolveIPAddr("ip", hostname)
		if err == nil {
			port.HostIP = ip.String()
		}
	}

	if b.config.HostIp != "" {
		port.HostIP = b.config.HostIp
	}

	metadata, metadataFromPort := serviceMetaData(container.Config, port.ExposedPort)

	ignore := mapDefault(metadata, "ignore", "")
	if ignore != "" {
		return nil
	}

	if b.config.RequireLabel {
		if strings.ToLower(mapDefault(metadata, "register", "false")) == "false" {
			log.Printf("Did not find label SERVICE_REGISTER on %s - ignoring.", container.Name)
			return nil
		}
	}

	service := new(Service)
	service.Origin = port
	service.ID = hostname + ":" + container.Name[1:] + ":" + port.ExposedPort
	service.Name = mapDefault(metadata, "name", defaultName)
	if isgroup && !metadataFromPort["name"] {
		service.Name += "-" + port.ExposedPort
	}
	var p int

	if b.config.Internal == true {
		service.IP = port.ExposedIP
		p, _ = strconv.Atoi(port.ExposedPort)
	} else {
		service.IP = port.HostIP
		p, _ = strconv.Atoi(port.HostPort)
	}
	service.Port = p

	if b.config.UseIpFromLabel != "" {
		containerIp := container.Config.Labels[b.config.UseIpFromLabel]
		if containerIp != "" {
			slashIndex := strings.LastIndex(containerIp, "/")
			if slashIndex > -1 {
				service.IP = containerIp[:slashIndex]
			} else {
				service.IP = containerIp
			}
			log.Println("using container IP " + service.IP + " from label '" +
				b.config.UseIpFromLabel + "'")
		} else {
			log.Println("Label '" + b.config.UseIpFromLabel +
				"' not found in container configuration")
		}
	}

	// NetworkMode can point to another container (kuberenetes pods)
	networkMode := container.HostConfig.NetworkMode
	if networkMode != "" {
		if strings.HasPrefix(networkMode, "container:") {
			networkContainerId := strings.Split(networkMode, ":")[1]
			log.Println(service.Name + ": detected container NetworkMode, linked to: " + networkContainerId[:12])
			networkContainer, err := b.docker.InspectContainer(networkContainerId)
			if err != nil {
				log.Println("unable to inspect network container:", networkContainerId[:12], err)
			} else {
				service.IP = networkContainer.NetworkSettings.IPAddress
				log.Println(service.Name + ": using network container IP " + service.IP)
			}
		}
	}

	if port.PortType == "udp" {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags, "udp")
		service.ID = service.ID + ":udp"
	} else {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags)
	}

	// Look for ECS labels and add them to metadata if present
	for k, v := range container.Config.Labels {
		if strings.Contains(k, "com.amazonaws.ecs") {
			metadata[k] = v
		}
	}

	id := mapDefault(metadata, "id", "")
	if id != "" {
		service.ID = id
	}

	delete(metadata, "id")
	delete(metadata, "tags")
	delete(metadata, "name")
	service.Attrs = metadata
	service.TTL = b.config.RefreshTtl

	return service
}

func (b *Bridge) remove(containerId string, deregister bool) {
	log.Printf("container stop detected for: %v", containerId)
	b.Lock()
	defer b.Unlock()

	if deregister {
		deregisterAll := func(services []*Service) {
			for _, service := range services {
				err := b.registry.Deregister(service)
				if err != nil {
					log.Println("deregister failed:", service.ID, err)
					continue
				}
				log.Println("removed:", containerId[:12], service.ID)
			}
		}
		deregisterAll(b.services[containerId])
		if d := b.deadContainers[containerId]; d != nil {
			deregisterAll(d.Services)
			delete(b.deadContainers, containerId)
		}
	} else if b.config.RefreshTtl != 0 && b.services[containerId] != nil {
		// need to stop the refreshing, but can't delete it yet
		b.deadContainers[containerId] = &DeadContainer{b.config.RefreshTtl, b.services[containerId]}
	}
	delete(b.services, containerId)
}

// bit set on ExitCode if it represents an exit via a signal
var dockerSignaledBit = 128

func (b *Bridge) shouldRemove(containerId string) bool {
	if b.config.DeregisterCheck == "always" {
		return true
	}
	container, err := b.docker.InspectContainer(containerId)
	if _, ok := err.(*dockerapi.NoSuchContainer); ok {
		// the container has already been removed from Docker
		// e.g. probabably run with "--rm" to remove immediately
		// so its exit code is not accessible
		log.Printf("registrator: container %v was removed, could not fetch exit code", containerId[:12])
		return true
	}

	switch {
	case err != nil:
		log.Printf("registrator: error fetching status for container %v on \"die\" event: %v\n", containerId[:12], err)
		return false
	case container.State.Running:
		log.Printf("registrator: not removing container %v, still running", containerId[:12])
		return false
	case container.State.ExitCode == 0:
		return true
	case container.State.ExitCode&dockerSignaledBit == dockerSignaledBit:
		return true
	}
	return false
}

var Hostname string

func init() {
	// It's ok for Hostname to ultimately be an empty string
	// An empty string will fall back to trying to make a best guess
	Hostname, _ = os.Hostname()
}
<commit_msg>Try to fix mutex wait on ELB registrations stalling heartbeats<commit_after>package bridge

import (
	"errors"
	"log"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"sync"

	dockerapi "github.com/fsouza/go-dockerclient"
)

var serviceIDPattern = regexp.MustCompile(`^(.+?):([a-zA-Z0-9][a-zA-Z0-9_.-]+):[0-9]+(?::udp)?$`)

type Bridge struct {
	sync.Mutex
	registry       RegistryAdapter
	docker         *dockerapi.Client
	services       map[string][]*Service
	deadContainers map[string]*DeadContainer
	config         Config
}

func New(docker *dockerapi.Client, adapterUri string, config Config) (*Bridge, error) {
	uri, err := url.Parse(adapterUri)
	if err != nil {
		return nil, errors.New("bad adapter uri: " + adapterUri)
	}
	factory, found := AdapterFactories.Lookup(uri.Scheme)
	if !found {
		return nil, errors.New("unrecognized adapter: " + adapterUri)
	}

	log.Println("Using", uri.Scheme, "adapter:", uri)
	return &Bridge{
		docker:         docker,
		config:         config,
		registry:       factory.New(uri),
		services:       make(map[string][]*Service),
		deadContainers: make(map[string]*DeadContainer),
	}, nil
}

func (b *Bridge) Ping() error {
	return b.registry.Ping()
}

func (b *Bridge) Add(containerId string) {
	b.add(containerId, false)
}

func (b *Bridge) Remove(containerId string) {
	b.remove(containerId, true)
}

func (b *Bridge) RemoveOnExit(containerId string) {
	b.remove(containerId, b.shouldRemove(containerId))
}

func (b *Bridge) Refresh() {
	for containerId, services := range b.getServicesCopy() {
		for _, service := range services {
			err := b.registry.Refresh(service)
			if err != nil {
				log.Println("refresh failed:", service.ID, err)
				continue
			}
			log.Println("refreshed:", containerId[:12], service.ID)
		}
	}
}

func (b *Bridge) PruneDeadContainers() {
	b.Lock()
	defer b.Unlock()
	for containerId, deadContainer := range b.deadContainers {
		deadContainer.TTL -= b.config.RefreshInterval
		if deadContainer.TTL <= 0 {
			delete(b.deadContainers, containerId)
		}
	}
}

// Get a deep copy of the current services in a thread-safe way
func (b *Bridge) getServicesCopy() map[string][]*Service {
	b.Lock()
	defer b.Unlock()
	svcsCopy := make(map[string][]*Service)

	for id, svc := range b.services {
		var svcPointers []*Service
		for _, s := range svc {
			t := *s
			z := &t
			svcPointers = append(svcPointers, z)
		}
		svcsCopy[id] = svcPointers
	}
	return svcsCopy
}

func (b *Bridge) Sync(quiet bool) {

	// Take this to avoid having to use a mutex
	servicesSnapshot := b.getServicesCopy()

	containers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{})
	if err != nil && quiet {
		log.Println("error listing containers, skipping sync")
		return
	} else if err != nil && !quiet {
		log.Fatal(err)
	}

	log.Printf("Syncing services on %d containers", len(containers))

	// NOTE: This assumes reregistering will do the right thing, i.e. nothing..
	for _, listing := range containers {
		services := servicesSnapshot[listing.ID]
		if services == nil {
			go b.add(listing.ID, quiet)
		} else {
			for _, service := range services {
				err := b.registry.Register(service)
				if err != nil {
					log.Println("sync register failed:", service, err)
				}
			}
		}
	}

	// Clean up services that were registered previously, but aren't
	// acknowledged within registrator
	if b.config.Cleanup {
		// Remove services if its corresponding container is not running
		log.Println("Listing non-exited containers")
		filters := map[string][]string{"status": {"created", "restarting", "running", "paused"}}
		nonExitedContainers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{Filters: filters})
		if err != nil {
			log.Println("error listing nonExitedContainers, skipping sync", err)
			return
		}
		for listingId, _ := range servicesSnapshot {
			found := false
			for _, container := range nonExitedContainers {
				if listingId == container.ID {
					found = true
					break
				}
			}
			// This is a container that does not exist
			if !found {
				log.Printf("stale: Removing service %s because it does not exist", listingId)
				go b.RemoveOnExit(listingId)
			}
		}

		log.Println("Cleaning up dangling services")
		extServices, err := b.registry.Services()
		if err != nil {
			log.Println("cleanup failed:", err)
			return
		}

	Outer:
		for _, extService := range extServices {
			matches := serviceIDPattern.FindStringSubmatch(extService.ID)
			if len(matches) != 3 {
				// There's no way this was registered by us, so leave it
				continue
			}
			serviceHostname := matches[1]
			if serviceHostname != Hostname {
				// ignore because registered on a different host
				continue
			}
			serviceContainerName := matches[2]
			for _, listing := range servicesSnapshot {
				for _, service := range listing {
					if service.Name == extService.Name && serviceContainerName == service.Origin.container.Name[1:] {
						continue Outer
					}
				}
			}
			log.Println("dangling:", extService.ID)
			err := b.registry.Deregister(extService)
			if err != nil {
				log.Println("deregister failed:", extService.ID, err)
				continue
			}
			log.Println(extService.ID, "removed")
		}
	}
}

func (b *Bridge) deleteDeadContainer(containerId string) {
	b.Lock()
	defer b.Unlock()

	if d := b.deadContainers[containerId]; d != nil {
		b.services[containerId] = d.Services
		delete(b.deadContainers, containerId)
	}
}

func (b *Bridge) appendService(containerId string, service *Service) {
	b.Lock()
	defer b.Unlock()
	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, will not append.")
		return
	}
	b.services[containerId] = append(b.services[containerId], service)
	log.Println("added:", containerId[:12], service.ID)
}

func (b *Bridge) add(containerId string, quiet bool) {
	b.deleteDeadContainer(containerId)

	b.Lock()
	defer b.Unlock()

	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, ignoring")
		// Alternatively, remove and readd or resubmit.
		return
	}
	b.Unlock()

	container, err := b.docker.InspectContainer(containerId)
	if err != nil {
		log.Println("unable to inspect container:", containerId[:12], err)
		return
	}

	ports := make(map[string]ServicePort)

	// Extract configured host port mappings, relevant when using --net=host
	for port, _ := range container.Config.ExposedPorts {
		published := []dockerapi.PortBinding{{"0.0.0.0", port.Port()}}
		ports[string(port)] = servicePort(container, port, published)
	}

	// Extract runtime port mappings, relevant when using --net=bridge
	for port, published := range container.NetworkSettings.Ports {
		ports[string(port)] = servicePort(container, port, published)
	}

	if len(ports) == 0 && !quiet {
		log.Println("ignored:", container.ID[:12], "no published ports")
		return
	}

	servicePorts := make(map[string]ServicePort)
	for key, port := range ports {
		if b.config.Internal != true && port.HostPort == "" {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "port", port.ExposedPort, "not published on host")
			}
			continue
		}
		servicePorts[key] = port
	}

	isGroup := len(servicePorts) > 1
	for _, port := range servicePorts {
		service := b.newService(port, isGroup)
		if service == nil {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "service on port", port.ExposedPort)
			}
			continue
		}
		err := b.registry.Register(service)
		if err != nil {
			log.Println("register failed:", service, err)
			continue
		}
		b.appendService(container.ID, service)
	}
}

func (b *Bridge) newService(port ServicePort, isgroup bool) *Service {
	container := port.container
	defaultName := strings.Split(path.Base(container.Config.Image), ":")[0]

	// not sure about this logic. kind of want to remove it.
	hostname := Hostname
	if hostname == "" {
		hostname = port.HostIP
	}
	if port.HostIP == "0.0.0.0" {
		ip, err := net.ResolveIPAddr("ip", hostname)
		if err == nil {
			port.HostIP = ip.String()
		}
	}

	if b.config.HostIp != "" {
		port.HostIP = b.config.HostIp
	}

	metadata, metadataFromPort := serviceMetaData(container.Config, port.ExposedPort)

	ignore := mapDefault(metadata, "ignore", "")
	if ignore != "" {
		return nil
	}

	if b.config.RequireLabel {
		if strings.ToLower(mapDefault(metadata, "register", "false")) == "false" {
			log.Printf("Did not find label SERVICE_REGISTER on %s - ignoring.", container.Name)
			return nil
		}
	}

	service := new(Service)
	service.Origin = port
	service.ID = hostname + ":" + container.Name[1:] + ":" + port.ExposedPort
	service.Name = mapDefault(metadata, "name", defaultName)
	if isgroup && !metadataFromPort["name"] {
		service.Name += "-" + port.ExposedPort
	}
	var p int

	if b.config.Internal == true {
		service.IP = port.ExposedIP
		p, _ = strconv.Atoi(port.ExposedPort)
	} else {
		service.IP = port.HostIP
		p, _ = strconv.Atoi(port.HostPort)
	}
	service.Port = p

	if b.config.UseIpFromLabel != "" {
		containerIp := container.Config.Labels[b.config.UseIpFromLabel]
		if containerIp != "" {
			slashIndex := strings.LastIndex(containerIp, "/")
			if slashIndex > -1 {
				service.IP = containerIp[:slashIndex]
			} else {
				service.IP = containerIp
			}
			log.Println("using container IP " + service.IP + " from label '" +
				b.config.UseIpFromLabel + "'")
		} else {
			log.Println("Label '" + b.config.UseIpFromLabel +
				"' not found in container configuration")
		}
	}

	// NetworkMode can point to another container (kuberenetes pods)
	networkMode := container.HostConfig.NetworkMode
	if networkMode != "" {
		if strings.HasPrefix(networkMode, "container:") {
			networkContainerId := strings.Split(networkMode, ":")[1]
			log.Println(service.Name + ": detected container NetworkMode, linked to: " + networkContainerId[:12])
			networkContainer, err := b.docker.InspectContainer(networkContainerId)
			if err != nil {
				log.Println("unable to inspect network container:", networkContainerId[:12], err)
			} else {
				service.IP = networkContainer.NetworkSettings.IPAddress
				log.Println(service.Name + ": using network container IP " + service.IP)
			}
		}
	}

	if port.PortType == "udp" {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags, "udp")
		service.ID = service.ID + ":udp"
	} else {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags)
	}

	// Look for ECS labels and add them to metadata if present
	for k, v := range container.Config.Labels {
		if strings.Contains(k, "com.amazonaws.ecs") {
			metadata[k] = v
		}
	}

	id := mapDefault(metadata, "id", "")
	if id != "" {
		service.ID = id
	}

	delete(metadata, "id")
	delete(metadata, "tags")
	delete(metadata, "name")
	service.Attrs = metadata
	service.TTL = b.config.RefreshTtl

	return service
}

func (b *Bridge) remove(containerId string, deregister bool) {
	log.Printf("container stop detected for: %v", containerId)
	b.Lock()
	defer b.Unlock()

	if deregister {
		deregisterAll := func(services []*Service) {
			for _, service := range services {
				err := b.registry.Deregister(service)
				if err != nil {
					log.Println("deregister failed:", service.ID, err)
					continue
				}
				log.Println("removed:", containerId[:12], service.ID)
			}
		}
		deregisterAll(b.services[containerId])
		if d := b.deadContainers[containerId]; d != nil {
			deregisterAll(d.Services)
			delete(b.deadContainers, containerId)
		}
	} else if b.config.RefreshTtl != 0 && b.services[containerId] != nil {
		// need to stop the refreshing, but can't delete it yet
		b.deadContainers[containerId] = &DeadContainer{b.config.RefreshTtl, b.services[containerId]}
	}
	delete(b.services, containerId)
}

// bit set on ExitCode if it represents an exit via a signal
var dockerSignaledBit = 128

func (b *Bridge) shouldRemove(containerId string) bool {
	if b.config.DeregisterCheck == "always" {
		return true
	}
	container, err := b.docker.InspectContainer(containerId)
	if _, ok := err.(*dockerapi.NoSuchContainer); ok {
		// the container has already been removed from Docker
		// e.g. probabably run with "--rm" to remove immediately
		// so its exit code is not accessible
		log.Printf("registrator: container %v was removed, could not fetch exit code", containerId[:12])
		return true
	}

	switch {
	case err != nil:
		log.Printf("registrator: error fetching status for container %v on \"die\" event: %v\n", containerId[:12], err)
		return false
	case container.State.Running:
		log.Printf("registrator: not removing container %v, still running", containerId[:12])
		return false
	case container.State.ExitCode == 0:
		return true
	case container.State.ExitCode&dockerSignaledBit == dockerSignaledBit:
		return true
	}
	return false
}

var Hostname string

func init() {
	// It's ok for Hostname to ultimately be an empty string
	// An empty string will fall back to trying to make a best guess
	Hostname, _ = os.Hostname()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"text/template"
	"time"
)

type Service struct {
	ContainterName string
	Name           string `json:"name"`
	BridgeName     string
	BridgeIP       string `json:"bridge-ip"`
	Pid            int
	Containers     map[string]Container
	NginxUpStream
}

type Container struct {
	Name        string
	ServiceName string `json:"service-name"`
	Command     string `json:"command"`
	Pid         int
	IP          string
	StartTime   time.Time
	VEth        string
}

type NginxUpStream struct {
	LoadBalanceType string
	Servers         []string
}

var services map[string]Service
var containers map[string]Container
var nginx_config *template.Template

const (
	bridgeNameBase = "brocker"
	vethNameBase   = "veth"
	MOUNT_LOC      = "/app"
	CONTAIN_DIR    = "/container"
)

func (c *Container) setName() {
	value := fmt.Sprintf("%s%s", c.StartTime, c.Command)
	sha := sha1.New()
	sha.Write([]byte(value))
	c.Name = hex.EncodeToString(sha.Sum(nil))[:8]
}

func (c *Container) Close() {
	if err := execInContainter("/bin/umount /app", c.Pid); err != nil {
		fmt.Println("Cannot unmount /app: ", err)
	}

	p, _ := os.FindProcess(c.Pid)
	p.Kill()
}

func (s *Service) reload() {
	if err := execInContainter("/usr/sbin/nginx -s reload -c /app/nginx.conf", s.Pid); err != nil {
		fmt.Println("Cannot reload nginx: ", err)
		return
	}
}

func (s *Service) Stop() {
	if err := execInContainter("/usr/sbin/nginx -s stop -c /app/nginx.conf", s.Pid); err != nil {
		fmt.Println(err)
	}

	for _, c := range s.Containers {
		c.Close()
	}

	delete_bridge := strings.Split(fmt.Sprintf("ip link delete %s type bridge", s.BridgeName), " ")
	if err := exec.Command(delete_bridge[0], delete_bridge[1:]...).Run(); err != nil {
		fmt.Printf("Cannot delete bridge %s", s.BridgeName)
	}
}

func (s *Service) writeConfig() {
	myappconffile, err := os.OpenFile(fmt.Sprintf("%s/%s/myapp.conf", CONTAIN_DIR, s.ContainterName), os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer myappconffile.Close()

	if err := nginx_config.ExecuteTemplate(myappconffile, "myapp.conf.tmpl", s); err != nil {
		fmt.Println(err)
		return
	}
}

func init() {
	services = make(map[string]Service)
	containers = make(map[string]Container)
	nginx_config = template.Must(template.ParseFiles("/etc/brocker/nginx.conf.tmpl", "/etc/brocker/myapp.conf.tmpl"))
}

func main() {
	ctrl_c := make(chan os.Signal, 1)
	signal.Notify(ctrl_c, os.Interrupt)
	go func() {
		for _ = range ctrl_c {
			for _, s := range services {
				s.Stop()
			}
			os.Exit(0)
		}
	}()

	http.HandleFunc("/api/v1/service/add", service_add)
	http.HandleFunc("/api/v1/container/run", container_run)
	http.HandleFunc("/api/v1/container/list", container_list)
	http.HandleFunc("/api/v1/container/exec", container_exec)
	http.HandleFunc("/api/v1/container/rm", container_rm)
	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		fmt.Println(err)
	}
}

func service_add(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	s := Service{
		Containers: make(map[string]Container),
	}

	if err := json.NewDecoder(r.Body).Decode(&s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[s.Name]; ok {
		http.Error(w, "Service already exists", http.StatusInternalServerError)
		return
	}

	s.BridgeName = fmt.Sprintf("%s%d", bridgeNameBase, len(services)+1)

	s.LoadBalanceType = "least_conn"
	if err := service_create_network(s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	path, err := exec.LookPath("nginx")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	c := Container{
		Name:        fmt.Sprintf("%s-nginx", s.Name),
		ServiceName: s.Name,
		Command:     fmt.Sprintf("%s -c %s", path, "/app/nginx.conf"),
	}

	go run(c, true)

	w.WriteHeader(http.StatusCreated)
}

func container_run(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	var c Container
	if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[c.ServiceName]; ok == false {
		http.Error(w, "Service does not exists", http.StatusInternalServerError)
		return
	}

	go run(c, false)

	w.WriteHeader(http.StatusCreated)
}

func container_list(w http.ResponseWriter, r *http.Request) {
	if err := json.NewEncoder(w).Encode(containers); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func container_exec(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	data := struct {
		Name string `json:"name"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	for _, c := range containers {
		if c.Name == data.Name {
			w.Write([]byte(fmt.Sprintf("%d", c.Pid)))
			return
		}
	}
}

func container_rm(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	data := struct {
		Name string `json:"name"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	c, ok := containers[data.Name]
	if !ok {
		http.Error(w, "Not a running container", http.StatusInternalServerError)
		return
	}
	c.Close()

	w.Write([]byte("Stopping container"))
}

func service_create_network(s Service) error {
	create_bridge := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type bridge", s.BridgeName), " ")
	set_bridge_up := strings.Split(fmt.Sprintf("/sbin/ip link set %s up", s.BridgeName), " ")
	set_bridge_ip := strings.Split(fmt.Sprintf("/sbin/ifconfig %s %s", s.BridgeName, s.BridgeIP), " ")

	if err := exec.Command(create_bridge[0], create_bridge[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_up[0], set_bridge_up[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_ip[0], set_bridge_ip[1:]...).Run(); err != nil {
		return err
	}

	services[s.Name] = s
	return nil
}

func run(c Container, isNginx bool) {
	fmt.Println("running parent")
	s := services[c.ServiceName]
	runcmd := "/home/yup/p/containers/brocker-run/brocker-run"

	c.StartTime = time.Now()
	c.setName()

	if err := os.Mkdir(fmt.Sprintf("%s/%s", CONTAIN_DIR, c.Name), 0644); err != nil {
		fmt.Println(err)
		return
	}

	if isNginx {
		nginxconffile, err := os.Create(fmt.Sprintf("%s/%s/nginx.conf", CONTAIN_DIR, c.Name))
		if err != nil {
			fmt.Println(err)
			nginxconffile.Close()
			return
		}

		if err := nginx_config.ExecuteTemplate(nginxconffile, "nginx.conf.tmpl", s); err != nil {
			fmt.Println(err)
			nginxconffile.Close()
			return
		}
		nginxconffile.Close()

		myappconffile, err := os.Create(fmt.Sprintf("%s/%s/myapp.conf", CONTAIN_DIR, c.Name))
		if err != nil {
			fmt.Println(err)
			myappconffile.Close()
			return
		}

		if err := nginx_config.ExecuteTemplate(myappconffile, "myapp.conf.tmpl", s); err != nil {
			fmt.Println(err)
			myappconffile.Close()
			return
		}
		myappconffile.Close()
	}

	args := strings.Split(fmt.Sprintf("%s %s %s", runcmd, c.Name, c.Command), " ")

	cmd := &exec.Cmd{
		Path: runcmd,
		Args: args,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWPID |
			syscall.CLONE_NEWNS |
			syscall.CLONE_NEWNET,
	}

	if err := cmd.Start(); err != nil {
		fmt.Println(err)
	}

	c.Pid = cmd.Process.Pid
	c.VEth = fmt.Sprintf("%s%d", vethNameBase, len(containers))
	link := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type veth peer name veth1 netns %d", c.VEth, c.Pid), " ")
	if err := exec.Command(link[0], link[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	uplink := strings.Split(fmt.Sprintf("/sbin/ifconfig %s up", c.VEth), " ")
	if err := exec.Command(uplink[0], uplink[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridge := strings.Split(fmt.Sprintf("/sbin/ip link set %s master %s", c.VEth, s.BridgeName), " ")
	if err := exec.Command(bridge[0], bridge[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridgeip := net.ParseIP(s.BridgeIP)
	lastOctet := bridgeip[15] + byte(len(s.Containers)+1)
	ip := net.IPv4(bridgeip[12], bridgeip[13], bridgeip[14], lastOctet)
	c.IP = ip.String()

	if err := execInContainter(fmt.Sprintf("/sbin/ifconfig veth1 %s", ip.String()), c.Pid); err != nil {
		fmt.Println(err)
		return
	}

	containers[c.Name] = c
	s.Containers[c.Name] = c

	if isNginx {
		s.Pid = c.Pid
		s.ContainterName = c.Name
	} else {
		s.Servers = append(s.Servers, fmt.Sprintf("%s:8080", c.IP))
		s.writeConfig()
		s.reload()
	}
	services[c.ServiceName] = s

	fmt.Println(cmd.Process.Pid)

	cmd.Wait()

	delete(containers, c.Name)
	delete(services[c.ServiceName].Containers, c.Name)
}

func execInContainter(cmd string, pid int) error {
	command := strings.Split(fmt.Sprintf("nsenter --target %d --pid --net --mount %s", pid, cmd), " ")
	if err := exec.Command(command[0], command[1:]...).Run(); err != nil {
		return err
	}

	return nil
}
<commit_msg>brocker-run is not tied to yup home<commit_after>package main

import (
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"
	"text/template"
	"time"
)

type Service struct {
	ContainterName string
	Name           string `json:"name"`
	BridgeName     string
	BridgeIP       string `json:"bridge-ip"`
	Pid            int
	Containers     map[string]Container
	NginxUpStream
}

type Container struct {
	Name        string
	ServiceName string `json:"service-name"`
	Command     string `json:"command"`
	Pid         int
	IP          string
	StartTime   time.Time
	VEth        string
}

type NginxUpStream struct {
	LoadBalanceType string
	Servers         []string
}

var services map[string]Service
var containers map[string]Container
var nginx_config *template.Template

const (
	bridgeNameBase = "brocker"
	vethNameBase   = "veth"
	MOUNT_LOC      = "/app"
	CONTAIN_DIR    = "/container"
)

func (c *Container) setName() {
	value := fmt.Sprintf("%s%s", c.StartTime, c.Command)
	sha := sha1.New()
	sha.Write([]byte(value))
	c.Name = hex.EncodeToString(sha.Sum(nil))[:8]
}

func (c *Container) Close() {
	if err := execInContainter("/bin/umount /app", c.Pid); err != nil {
		fmt.Println("Cannot unmount /app: ", err)
	}

	p, _ := os.FindProcess(c.Pid)
	p.Kill()
}

func (s *Service) reload() {
	if err := execInContainter("/usr/sbin/nginx -s reload -c /app/nginx.conf", s.Pid); err != nil {
		fmt.Println("Cannot reload nginx: ", err)
		return
	}
}

func (s *Service) Stop() {
	if err := execInContainter("/usr/sbin/nginx -s stop -c /app/nginx.conf", s.Pid); err != nil {
		fmt.Println(err)
	}

	for _, c := range s.Containers {
		c.Close()
	}

	delete_bridge := strings.Split(fmt.Sprintf("ip link delete %s type bridge", s.BridgeName), " ")
	if err := exec.Command(delete_bridge[0], delete_bridge[1:]...).Run(); err != nil {
		fmt.Printf("Cannot delete bridge %s", s.BridgeName)
	}
}

func (s *Service) writeConfig() {
	myappconffile, err := os.OpenFile(fmt.Sprintf("%s/%s/myapp.conf", CONTAIN_DIR, s.ContainterName), os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer myappconffile.Close()

	if err := nginx_config.ExecuteTemplate(myappconffile, "myapp.conf.tmpl", s); err != nil {
		fmt.Println(err)
		return
	}
}

func init() {
	services = make(map[string]Service)
	containers = make(map[string]Container)
	nginx_config = template.Must(template.ParseFiles("/etc/brocker/nginx.conf.tmpl", "/etc/brocker/myapp.conf.tmpl"))
}

func main() {
	ctrl_c := make(chan os.Signal, 1)
	signal.Notify(ctrl_c, os.Interrupt)
	go func() {
		for _ = range ctrl_c {
			for _, s := range services {
				s.Stop()
			}
			os.Exit(0)
		}
	}()

	http.HandleFunc("/api/v1/service/add", service_add)
	http.HandleFunc("/api/v1/container/run", container_run)
	http.HandleFunc("/api/v1/container/list", container_list)
	http.HandleFunc("/api/v1/container/exec", container_exec)
	http.HandleFunc("/api/v1/container/rm", container_rm)
	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		fmt.Println(err)
	}
}

func service_add(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	s := Service{
		Containers: make(map[string]Container),
	}

	if err := json.NewDecoder(r.Body).Decode(&s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[s.Name]; ok {
		http.Error(w, "Service already exists", http.StatusInternalServerError)
		return
	}

	s.BridgeName = fmt.Sprintf("%s%d", bridgeNameBase, len(services)+1)

	s.LoadBalanceType = "least_conn"
	if err := service_create_network(s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	path, err := exec.LookPath("nginx")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	c := Container{
		Name:        fmt.Sprintf("%s-nginx", s.Name),
		ServiceName: s.Name,
		Command:     fmt.Sprintf("%s -c %s", path, "/app/nginx.conf"),
	}

	go run(c, true)

	w.WriteHeader(http.StatusCreated)
}

func container_run(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	var c Container
	if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[c.ServiceName]; ok == false {
		http.Error(w, "Service does not exists", http.StatusInternalServerError)
		return
	}

	go run(c, false)

	w.WriteHeader(http.StatusCreated)
}

func container_list(w http.ResponseWriter, r *http.Request) {
	if err := json.NewEncoder(w).Encode(containers); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func container_exec(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	data := struct {
		Name string `json:"name"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	for _, c := range containers {
		if c.Name == data.Name {
			w.Write([]byte(fmt.Sprintf("%d", c.Pid)))
			return
		}
	}
}

func container_rm(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	data := struct {
		Name string `json:"name"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	c, ok := containers[data.Name]
	if !ok {
		http.Error(w, "Not a running container", http.StatusInternalServerError)
		return
	}
	c.Close()

	w.Write([]byte("Stopping container"))
}

func service_create_network(s Service) error {
	create_bridge := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type bridge", s.BridgeName), " ")
	set_bridge_up := strings.Split(fmt.Sprintf("/sbin/ip link set %s up", s.BridgeName), " ")
	set_bridge_ip := strings.Split(fmt.Sprintf("/sbin/ifconfig %s %s", s.BridgeName, s.BridgeIP), " ")

	if err := exec.Command(create_bridge[0], create_bridge[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_up[0], set_bridge_up[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_ip[0], set_bridge_ip[1:]...).Run(); err != nil {
		return err
	}

	services[s.Name] = s
	return nil
}

func run(c Container, isNginx bool) {
	fmt.Println("running parent")
	s := services[c.ServiceName]
	runcmd, err := exec.LookPath("brocker-run")
	if err != nil {
		fmt.Println(err)
		return
	}

	c.StartTime = time.Now()
	c.setName()

	if err := os.Mkdir(fmt.Sprintf("%s/%s", CONTAIN_DIR, c.Name), 0644); err != nil {
		fmt.Println(err)
		return
	}

	if isNginx {
		nginxconffile, err := os.Create(fmt.Sprintf("%s/%s/nginx.conf", CONTAIN_DIR, c.Name))
		if err != nil {
			fmt.Println(err)
			nginxconffile.Close()
			return
		}

		if err := nginx_config.ExecuteTemplate(nginxconffile, "nginx.conf.tmpl", s); err != nil {
			fmt.Println(err)
			nginxconffile.Close()
			return
		}
		nginxconffile.Close()

		myappconffile, err := os.Create(fmt.Sprintf("%s/%s/myapp.conf", CONTAIN_DIR, c.Name))
		if err != nil {
			fmt.Println(err)
			myappconffile.Close()
			return
		}

		if err := nginx_config.ExecuteTemplate(myappconffile, "myapp.conf.tmpl", s); err != nil {
			fmt.Println(err)
			myappconffile.Close()
			return
		}
		myappconffile.Close()
	}

	args := strings.Split(fmt.Sprintf("%s %s %s", runcmd, c.Name, c.Command), " ")

	cmd := &exec.Cmd{
		Path: runcmd,
		Args: args,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWPID |
			syscall.CLONE_NEWNS |
			syscall.CLONE_NEWNET,
	}

	if err := cmd.Start(); err != nil {
		fmt.Println(err)
	}

	c.Pid = cmd.Process.Pid
	c.VEth = fmt.Sprintf("%s%d", vethNameBase, len(containers))
	link := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type veth peer name veth1 netns %d", c.VEth, c.Pid), " ")
	if err := exec.Command(link[0], link[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	uplink := strings.Split(fmt.Sprintf("/sbin/ifconfig %s up", c.VEth), " ")
	if err := exec.Command(uplink[0], uplink[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridge := strings.Split(fmt.Sprintf("/sbin/ip link set %s master %s", c.VEth, s.BridgeName), " ")
	if err := exec.Command(bridge[0], bridge[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridgeip := net.ParseIP(s.BridgeIP)
	lastOctet := bridgeip[15] + byte(len(s.Containers)+1)
	ip := net.IPv4(bridgeip[12], bridgeip[13], bridgeip[14], lastOctet)
	c.IP = ip.String()

	if err := execInContainter(fmt.Sprintf("/sbin/ifconfig veth1 %s", ip.String()), c.Pid); err != nil {
		fmt.Println(err)
		return
	}

	containers[c.Name] = c
	s.Containers[c.Name] = c

	if isNginx {
		s.Pid = c.Pid
		s.ContainterName = c.Name
	} else {
		s.Servers = append(s.Servers, fmt.Sprintf("%s:8080", c.IP))
		s.writeConfig()
		s.reload()
	}
	services[c.ServiceName] = s

	fmt.Println(cmd.Process.Pid)

	cmd.Wait()

	delete(containers, c.Name)
	delete(services[c.ServiceName].Containers, c.Name)
}

func execInContainter(cmd string, pid int) error {
	command := strings.Split(fmt.Sprintf("nsenter --target %d --pid --net --mount %s", pid, cmd), " ")
	if err := exec.Command(command[0], command[1:]...).Run(); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package lib

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Client is the API client that performs all operations
// against a docker server.
type Client struct {
	// proto holds the client protocol i.e. unix.
	proto string
	// addr holds the client address.
	addr string
	// basePath holds the path to prepend to the requests
	basePath string
	// scheme holds the scheme of the client i.e. https.
	scheme string
	// tlsConfig holds the tls configuration to use in hijacked requests.
	tlsConfig *tls.Config
	// httpClient holds the client transport instance. Exported to keep the old code running.
	httpClient *http.Client
	// version of the server to talk to.
	version string
	// custom http headers configured by users
	customHTTPHeaders map[string]string
}

// NewEnvClient initializes a new API client based on environment variables.
// Use DOCKER_HOST to set the url to the docker server.
// Use DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
// Use DOCKER_CERT_PATH to load the tls certificates from.
func NewEnvClient() (*Client, error) {
	var transport *http.Transport
	if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
		tlsc := &tls.Config{}

		cert, err := tls.LoadX509KeyPair(filepath.Join(dockerCertPath, "cert.pem"), filepath.Join(dockerCertPath, "key.pem"))
		if err != nil {
			return nil, fmt.Errorf("Error loading x509 key pair: %s", err)
		}

		tlsc.Certificates = append(tlsc.Certificates, cert)
		tlsc.InsecureSkipVerify = os.Getenv("DOCKER_TLS_VERIFY") == ""
		transport = &http.Transport{
			TLSClientConfig: tlsc,
		}
	}

	return NewClient(os.Getenv("DOCKER_HOST"), os.Getenv("DOCKER_API_VERSION"), transport, nil)
}

// NewClient initializes a new API client for the given host and API version.
// It won't send any version information if the version number is empty.
// It uses the transport to create a new http client.
// It also initializes the custom http headers to add to each request.
func NewClient(host string, version string, transport *http.Transport, httpHeaders map[string]string) (*Client, error) {
	var (
		basePath       string
		tlsConfig      *tls.Config
		scheme         = "http"
		protoAddrParts = strings.SplitN(host, "://", 2)
		proto, addr    = protoAddrParts[0], protoAddrParts[1]
	)

	if proto == "tcp" {
		parsed, err := url.Parse("tcp://" + addr)
		if err != nil {
			return nil, err
		}
		addr = parsed.Host
		basePath = parsed.Path
	}

	transport = configureTransport(transport, proto, addr)
	if transport.TLSClientConfig != nil {
		scheme = "https"
	}

	return &Client{
		proto:             proto,
		addr:              addr,
		basePath:          basePath,
		scheme:            scheme,
		tlsConfig:         tlsConfig,
		httpClient:        &http.Client{Transport: transport},
		version:           version,
		customHTTPHeaders: httpHeaders,
	}, nil
}

// getAPIPath returns the versioned request path to call the api.
// It appends the query parameters to the path if they are not empty.
func (cli *Client) getAPIPath(p string, query url.Values) string {
	var apiPath string
	if cli.version != "" {
		v := strings.TrimPrefix(cli.version, "v")
		apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
	} else {
		apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
	}
	if len(query) > 0 {
		apiPath += "?" + query.Encode()
	}
	return apiPath
}

// ClientVersion returns the version string associated with this
// instance of the Client. Note that this value can be changed
// via the DOCKER_API_VERSION env var.
func (cli *Client) ClientVersion() string {
	return cli.version
}

func configureTransport(tr *http.Transport, proto, addr string) *http.Transport {
	if tr == nil {
		tr = &http.Transport{}
	}

	// Why 32? See https://github.com/docker/docker/pull/8035.
	timeout := 32 * time.Second
	if proto == "unix" {
		// No need for compression in local communications.
		tr.DisableCompression = true
		tr.Dial = func(_, _ string) (net.Conn, error) {
			return net.DialTimeout(proto, addr, timeout)
		}
	} else {
		tr.Proxy = http.ProxyFromEnvironment
		tr.Dial = (&net.Dialer{Timeout: timeout}).Dial
	}

	return tr
}
<commit_msg>Add godoc comment about client tls verification.<commit_after>package lib

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Client is the API client that performs all operations
// against a docker server.
type Client struct {
	// proto holds the client protocol i.e. unix.
	proto string
	// addr holds the client address.
	addr string
	// basePath holds the path to prepend to the requests
	basePath string
	// scheme holds the scheme of the client i.e. https.
	scheme string
	// tlsConfig holds the tls configuration to use in hijacked requests.
	tlsConfig *tls.Config
	// httpClient holds the client transport instance. Exported to keep the old code running.
	httpClient *http.Client
	// version of the server to talk to.
	version string
	// custom http headers configured by users
	customHTTPHeaders map[string]string
}

// NewEnvClient initializes a new API client based on environment variables.
// Use DOCKER_HOST to set the url to the docker server.
// Use DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
// Use DOCKER_CERT_PATH to load the tls certificates from.
// Use DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
func NewEnvClient() (*Client, error) {
	var transport *http.Transport
	if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
		tlsc := &tls.Config{}

		cert, err := tls.LoadX509KeyPair(filepath.Join(dockerCertPath, "cert.pem"), filepath.Join(dockerCertPath, "key.pem"))
		if err != nil {
			return nil, fmt.Errorf("Error loading x509 key pair: %s", err)
		}

		tlsc.Certificates = append(tlsc.Certificates, cert)
		tlsc.InsecureSkipVerify = os.Getenv("DOCKER_TLS_VERIFY") == ""
		transport = &http.Transport{
			TLSClientConfig: tlsc,
		}
	}

	return NewClient(os.Getenv("DOCKER_HOST"), os.Getenv("DOCKER_API_VERSION"), transport, nil)
}

// NewClient initializes a new API client for the given host and API version.
// It won't send any version information if the version number is empty.
// It uses the transport to create a new http client.
// It also initializes the custom http headers to add to each request.
func NewClient(host string, version string, transport *http.Transport, httpHeaders map[string]string) (*Client, error) {
	var (
		basePath       string
		tlsConfig      *tls.Config
		scheme         = "http"
		protoAddrParts = strings.SplitN(host, "://", 2)
		proto, addr    = protoAddrParts[0], protoAddrParts[1]
	)

	if proto == "tcp" {
		parsed, err := url.Parse("tcp://" + addr)
		if err != nil {
			return nil, err
		}
		addr = parsed.Host
		basePath = parsed.Path
	}

	transport = configureTransport(transport, proto, addr)
	if transport.TLSClientConfig != nil {
		scheme = "https"
	}

	return &Client{
		proto:             proto,
		addr:              addr,
		basePath:          basePath,
		scheme:            scheme,
		tlsConfig:         tlsConfig,
		httpClient:        &http.Client{Transport: transport},
		version:           version,
		customHTTPHeaders: httpHeaders,
	}, nil
}

// getAPIPath returns the versioned request path to call the api.
// It appends the query parameters to the path if they are not empty.
func (cli *Client) getAPIPath(p string, query url.Values) string {
	var apiPath string
	if cli.version != "" {
		v := strings.TrimPrefix(cli.version, "v")
		apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
	} else {
		apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
	}
	if len(query) > 0 {
		apiPath += "?" + query.Encode()
	}
	return apiPath
}

// ClientVersion returns the version string associated with this
// instance of the Client. Note that this value can be changed
// via the DOCKER_API_VERSION env var.
func (cli *Client) ClientVersion() string {
	return cli.version
}

func configureTransport(tr *http.Transport, proto, addr string) *http.Transport {
	if tr == nil {
		tr = &http.Transport{}
	}

	// Why 32? See https://github.com/docker/docker/pull/8035.
	timeout := 32 * time.Second
	if proto == "unix" {
		// No need for compression in local communications.
		tr.DisableCompression = true
		tr.Dial = func(_, _ string) (net.Conn, error) {
			return net.DialTimeout(proto, addr, timeout)
		}
	} else {
		tr.Proxy = http.ProxyFromEnvironment
		tr.Dial = (&net.Dialer{Timeout: timeout}).Dial
	}

	return tr
}
<|endoftext|>


<commit_before>package netutil

import (
	"bytes"
	"net"
	"strings"
)

/* Based on:
https://husobee.github.io/golang/ip-address/2015/12/17/remote-ip-go.html requested at:
https://github.com/kataras/iris/issues/1453
*/

// IPRange is a structure that holds the start and end of a range of IP Addresses.
type IPRange struct {
	Start net.IP `json:"start" yaml:"Start" toml"Start"`
	End   net.IP `json:"end" yaml:"End" toml"End"`
}

// IPInRange reports whether a given IP Address is within a range given.
func IPInRange(r IPRange, ipAddress net.IP) bool {
	return bytes.Compare(ipAddress, r.Start) >= 0 && bytes.Compare(ipAddress, r.End) < 0
}

// IPIsPrivateSubnet reports whether this "ipAddress" is in a private subnet.
func IPIsPrivateSubnet(ipAddress net.IP, privateRanges []IPRange) bool {
	// IPv4 for now.
	if ipCheck := ipAddress.To4(); ipCheck != nil {
		// iterate over all our ranges.
		for _, r := range privateRanges {
			// check if this ip is in a private range.
			if IPInRange(r, ipAddress) {
				return true
			}
		}
	}
	return false
}

// GetIPAddress returns a valid public IP Address from a collection of IP Addresses
// and a range of private subnets.
//
// Reports whether a valid IP was found.
func GetIPAddress(ipAddresses []string, privateRanges []IPRange) (string, bool) {
	// march from right to left until we get a public address
	// that will be the address right before our proxy.
	for i := len(ipAddresses) - 1; i >= 0; i-- {
		ip := strings.TrimSpace(ipAddresses[i])
		realIP := net.ParseIP(ip)
		if !realIP.IsGlobalUnicast() || IPIsPrivateSubnet(realIP, privateRanges) {
			// bad address, go to next
			continue
		}
		return ip, true

	}

	return "", false
}
<commit_msg>fix typo<commit_after>package netutil

import (
	"bytes"
	"net"
	"strings"
)

/* Based on:
https://husobee.github.io/golang/ip-address/2015/12/17/remote-ip-go.html requested at:
https://github.com/kataras/iris/issues/1453
*/

// IPRange is a structure that holds the start and end of a range of IP Addresses.
type IPRange struct {
	Start net.IP `json:"start" yaml:"Start" toml:"Start"`
	End   net.IP `json:"end" yaml:"End" toml:"End"`
}

// IPInRange reports whether a given IP Address is within a range given.
func IPInRange(r IPRange, ipAddress net.IP) bool {
	return bytes.Compare(ipAddress, r.Start) >= 0 && bytes.Compare(ipAddress, r.End) < 0
}

// IPIsPrivateSubnet reports whether this "ipAddress" is in a private subnet.
func IPIsPrivateSubnet(ipAddress net.IP, privateRanges []IPRange) bool {
	// IPv4 for now.
	if ipCheck := ipAddress.To4(); ipCheck != nil {
		// iterate over all our ranges.
		for _, r := range privateRanges {
			// check if this ip is in a private range.
			if IPInRange(r, ipAddress) {
				return true
			}
		}
	}
	return false
}

// GetIPAddress returns a valid public IP Address from a collection of IP Addresses
// and a range of private subnets.
//
// Reports whether a valid IP was found.
func GetIPAddress(ipAddresses []string, privateRanges []IPRange) (string, bool) {
	// march from right to left until we get a public address
	// that will be the address right before our proxy.
	for i := len(ipAddresses) - 1; i >= 0; i-- {
		ip := strings.TrimSpace(ipAddresses[i])
		realIP := net.ParseIP(ip)
		if !realIP.IsGlobalUnicast() || IPIsPrivateSubnet(realIP, privateRanges) {
			// bad address, go to next
			continue
		}
		return ip, true

	}

	return "", false
}
<|endoftext|>


<commit_before>package middleware

import (
	"bytes"
	"context"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	opentracing "github.com/opentracing/opentracing-go"
	log "github.com/sirupsen/logrus"
	jaeger "github.com/uber/jaeger-client-go"
	macaron "gopkg.in/macaron.v1"
)

var (
	LogHeaders = false
)

type LoggingResponseWriter struct {
	macaron.ResponseWriter
	errBody []byte // the body in case it is an error
}

func (rw *LoggingResponseWriter) Write(b []byte) (int, error) {
	if rw.ResponseWriter.Status() >= 400 {
		rw.errBody = make([]byte, len(b))
		copy(rw.errBody, b)
	}
	return rw.ResponseWriter.Write(b)
}

func Logger() macaron.Handler {
	return func(ctx *Context) {
		start := time.Now()
		rw := &LoggingResponseWriter{
			ResponseWriter: ctx.Resp,
		}
		ctx.Resp = rw
		ctx.MapTo(ctx.Resp, (*http.ResponseWriter)(nil))
		ctx.Next()

		// Only log:
		// - requests that resulted in errors
		// - requests on /render path
		if rw.Status() >= 200 && rw.Status() < 300 && !strings.HasPrefix(ctx.Req.URL.Path, "/render") {
			return
		}

		var content strings.Builder
		fmt.Fprintf(&content, "ts=%s", time.Now().Format(time.RFC3339Nano))

		traceID, _ := extractTraceID(ctx.Req.Context())
		if traceID != "" {
			fmt.Fprintf(&content, " traceID=%s", traceID)
		}

		err := ctx.Req.ParseForm()
		if err != nil {
			log.Errorf("Could not parse http request: %v", err)
		}
		paramsAsString := ""
		if len(ctx.Req.Form) > 0 {
			paramsAsString += "?"
			paramsAsString += ctx.Req.Form.Encode()
		}
		fmt.Fprintf(&content, " msg=\"%s %s%s (%v) %v\" orgID=%d", ctx.Req.Method, ctx.Req.URL.Path, paramsAsString, rw.Status(), time.Since(start), ctx.OrgId)

		referer := ctx.Req.Referer()
		if referer != "" {
			fmt.Fprintf(&content, " referer=%s", referer)
		}
		sourceIP := ctx.RemoteAddr()
		if sourceIP != "" {
			fmt.Fprintf(&content, " sourceIP=\"%s\"", sourceIP)
		}

		if rw.Status() < 200 || rw.Status() >= 300 {
			errorMsg := url.PathEscape(string(rw.errBody))
			fmt.Fprintf(&content, " error=\"%s\"", errorMsg)
		}

		if LogHeaders {
			headers, err := extractHeaders(ctx.Req.Request)
			if err != nil {
				log.Errorf("Could not extract request headers: %v", err)
			}
			fmt.Fprintf(&content, " headers=\"%s\"", string(headers))
		}

		log.Println(content.String())
	}
}

func extractHeaders(req *http.Request) (string, error) {
	var b bytes.Buffer

	// Exclude some headers for security, or just that we don't need them when debugging
	err := req.Header.WriteSubset(&b, map[string]bool{
		"Cookie":        true,
		"X-Csrf-Token":  true,
		"Authorization": true,
	})
	if err != nil {
		return "", err
	}
	return url.PathEscape(string(b.Bytes())), nil
}

func extractTraceID(ctx context.Context) (string, bool) {
	sp := opentracing.SpanFromContext(ctx)
	if sp == nil {
		return "", false
	}
	sctx, ok := sp.Context().(jaeger.SpanContext)
	if !ok {
		return "", false
	}

	return sctx.TraceID().String(), true
}
<commit_msg>Log if trace is sampled<commit_after>package middleware

import (
	"bytes"
	"context"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	opentracing "github.com/opentracing/opentracing-go"
	log "github.com/sirupsen/logrus"
	jaeger "github.com/uber/jaeger-client-go"
	macaron "gopkg.in/macaron.v1"
)

var (
	LogHeaders = false
)

type LoggingResponseWriter struct {
	macaron.ResponseWriter
	errBody []byte // the body in case it is an error
}

func (rw *LoggingResponseWriter) Write(b []byte) (int, error) {
	if rw.ResponseWriter.Status() >= 400 {
		rw.errBody = make([]byte, len(b))
		copy(rw.errBody, b)
	}
	return rw.ResponseWriter.Write(b)
}

func Logger() macaron.Handler {
	return func(ctx *Context) {
		start := time.Now()
		rw := &LoggingResponseWriter{
			ResponseWriter: ctx.Resp,
		}
		ctx.Resp = rw
		ctx.MapTo(ctx.Resp, (*http.ResponseWriter)(nil))
		ctx.Next()

		// Only log:
		// - requests that resulted in errors
		// - requests on /render path
		if rw.Status() >= 200 && rw.Status() < 300 && !strings.HasPrefix(ctx.Req.URL.Path, "/render") {
			return
		}

		var content strings.Builder
		fmt.Fprintf(&content, "ts=%s", time.Now().Format(time.RFC3339Nano))

		traceID, sampled := extractTraceID(ctx.Req.Context())
		if traceID != "" {
			fmt.Fprintf(&content, " traceID=%s, sampled=%t", traceID, sampled)
		}

		err := ctx.Req.ParseForm()
		if err != nil {
			log.Errorf("Could not parse http request: %v", err)
		}
		paramsAsString := ""
		if len(ctx.Req.Form) > 0 {
			paramsAsString += "?"
			paramsAsString += ctx.Req.Form.Encode()
		}

		fmt.Fprintf(&content, " msg=\"%s %s%s (%v) %v\" orgID=%d", ctx.Req.Method, ctx.Req.URL.Path, paramsAsString, rw.Status(), time.Since(start), ctx.OrgId)

		referer := ctx.Req.Referer()
		if referer != "" {
			fmt.Fprintf(&content, " referer=%s", referer)
		}
		sourceIP := ctx.RemoteAddr()
		if sourceIP != "" {
			fmt.Fprintf(&content, " sourceIP=\"%s\"", sourceIP)
		}

		if rw.Status() < 200 || rw.Status() >= 300 {
			errorMsg := url.PathEscape(string(rw.errBody))
			fmt.Fprintf(&content, " error=\"%s\"", errorMsg)
		}

		if LogHeaders {
			headers, err := extractHeaders(ctx.Req.Request)
			if err != nil {
				log.Errorf("Could not extract request headers: %v", err)
			}
			fmt.Fprintf(&content, " headers=\"%s\"", string(headers))
		}

		log.Println(content.String())
	}
}

func extractHeaders(req *http.Request) (string, error) {
	var b bytes.Buffer

	// Exclude some headers for security, or just that we don't need them when debugging
	err := req.Header.WriteSubset(&b, map[string]bool{
		"Cookie":        true,
		"X-Csrf-Token":  true,
		"Authorization": true,
	})
	if err != nil {
		return "", err
	}
	return url.PathEscape(string(b.Bytes())), nil
}

func extractTraceID(ctx context.Context) (string, bool) {
	sp := opentracing.SpanFromContext(ctx)
	if sp == nil {
		return "", false
	}
	sctx, ok := sp.Context().(jaeger.SpanContext)
	if !ok {
		return "", false
	}

	return sctx.TraceID().String(), sctx.IsSampled()
}
<|endoftext|>


<commit_before>package system

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

	"github.com/albertoleal/backstage/api/context"
	"github.com/albertoleal/backstage/auth"
	"github.com/albertoleal/backstage/errors"
	"github.com/zenazn/goji/web"
	. "github.com/zenazn/goji/web/middleware"
)

func AuthorizationMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		authorization := r.Header.Get("Authorization")
		user, err := auth.GetUserFromToken(authorization)
		if err != nil {
			context.AddRequestError(c, &errors.HTTPError{StatusCode: http.StatusUnauthorized, Message: "You do not have access to this resource."})
			return
		}
		context.SetCurrentUser(c, user)
		h.ServeHTTP(w, r)
	}

	return http.HandlerFunc(fn)
}

func ErrorHandlerMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		h.ServeHTTP(w, r)
		key, ok := context.GetRequestError(c)
		if ok {
			body, _ := json.Marshal(key)
			w.WriteHeader(key.StatusCode)
			io.WriteString(w, string(body))
		}
	}

	return http.HandlerFunc(fn)
}

func RequestIdMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		reqId := GetReqID(*c)
		w.Header().Set("Request-Id", reqId)
		h.ServeHTTP(w, r)
	}

	return http.HandlerFunc(fn)
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
	notFound := &errors.HTTPError{StatusCode: http.StatusNotFound, Message: "The resource you are looking for was not found."}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(notFound.StatusCode)
	body, _ := json.Marshal(notFound)
	fmt.Fprint(w, string(body))
	return
}
<commit_msg>Whitespace<commit_after>package system

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

	"github.com/albertoleal/backstage/api/context"
	"github.com/albertoleal/backstage/auth"
	"github.com/albertoleal/backstage/errors"
	"github.com/zenazn/goji/web"
	. "github.com/zenazn/goji/web/middleware"
)

func AuthorizationMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		authorization := r.Header.Get("Authorization")
		user, err := auth.GetUserFromToken(authorization)
		if err != nil {
			context.AddRequestError(c, &errors.HTTPError{StatusCode: http.StatusUnauthorized, Message: "You do not have access to this resource."})
			return
		}
		context.SetCurrentUser(c, user)
		h.ServeHTTP(w, r)
	}

	return http.HandlerFunc(fn)
}

func ErrorHandlerMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		h.ServeHTTP(w, r)
		key, ok := context.GetRequestError(c)
		if ok {
			body, _ := json.Marshal(key)
			w.WriteHeader(key.StatusCode)
			io.WriteString(w, string(body))
		}
	}

	return http.HandlerFunc(fn)
}

func RequestIdMiddleware(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		reqId := GetReqID(*c)
		w.Header().Set("Request-Id", reqId)
		h.ServeHTTP(w, r)
	}

	return http.HandlerFunc(fn)
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
	notFound := &errors.HTTPError{StatusCode: http.StatusNotFound, Message: "The resource you are looking for was not found."}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(notFound.StatusCode)
	body, _ := json.Marshal(notFound)
	fmt.Fprint(w, string(body))

	return
}
<|endoftext|>