<commit_before>// Copyright © 2009--2013 The Web.go Authors
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"io"

	"github.com/hraban/web"
)

func root(ctx *web.Context, name string) error {
	ws := ctx.WebsockConn
	ws.Write([]byte("hey " + name))
	io.Copy(ws, ws)
	return nil
}

func main() {
	web.Websocket("/(.*)", root)
	web.Run("0.0.0.0:8081")
}
<commit_msg>handle error in websocket example<commit_after>// Copyright © 2009--2013 The Web.go Authors
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"io"

	"github.com/hraban/web"
)

func root(ctx *web.Context, name string) error {
	ws := ctx.WebsockConn
	ws.Write([]byte("hey " + name))
	_, err := io.Copy(ws, ws)
	return err
}

func main() {
	web.Websocket("/(.*)", root)
	web.Run("0.0.0.0:8081")
}
<|endoftext|>


<commit_before>package explorer

import (
	"testing"

	"github.com/NebulousLabs/Sia/types"
)

// TestIntegrationExplorerActiveContractMetrics checks that the siacoin
// transfer volume metric is working correctly.
func TestIntegrationExplorerActiveContractMetrics(t *testing.T) {
	if testing.Short() {
		t.Skip()
	}

	et, err := createExplorerTester("TestIntegrationExporerActiveContractMetrics")
	if err != nil {
		t.Fatal(err)
	}
	// Propel explorer tester past the hardfork height.
	for i := 0; i < 10; i++ {
		_, err = et.miner.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
	if !et.explorer.activeContractCost.IsZero() {
		t.Error("fresh explorer has nonzero active contract cost")
	}
	if et.explorer.activeContractCount != 0 {
		t.Error("active contract count should initialize to zero")
	}
	if !et.explorer.activeContractSize.IsZero() {
		t.Error("active contract size should initialize to zero")
	}

	// Put a file contract into the chain, and check that the explorer
	// correctly does all of the counting.
	builder := et.wallet.StartTransaction()
	builder.FundSiacoins(types.NewCurrency64(5e9))
	fcOutputs := []types.SiacoinOutput{{Value: types.NewCurrency64(4805e6)}}
	fc := types.FileContract{
		FileSize:           5e3,
		WindowStart:        et.explorer.blockchainHeight + 2,
		WindowEnd:          et.explorer.blockchainHeight + 3,
		Payout:             types.NewCurrency64(5e9),
		ValidProofOutputs:  fcOutputs,
		MissedProofOutputs: fcOutputs,
	}
	_ = builder.AddFileContract(fc)
	txns, err := builder.Sign(true)
	if err != nil {
		t.Fatal(err)
	}
	err = et.tpool.AcceptTransactionSet(txns)
	if err != nil {
		t.Fatal(err)
	}
	_, err = et.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}

	// Check that the active stats have updated to represent the file contract.
	if et.explorer.activeContractCost.Cmp(types.NewCurrency64(5e9)) != 0 {
		t.Error("active resources providing wrong file contract cost")
	}
	if et.explorer.activeContractCount != 1 {
		t.Error("active contract count does not read correctly")
	}
	if et.explorer.activeContractSize.Cmp(types.NewCurrency64(5e3)) != 0 {
		t.Error("active contract size is not correctly reported")
	}

	// Perform some sort of reorg and check that the reorg is handled
	// correctly.
}
<commit_msg>add testing for expiring contracts<commit_after>package explorer

import (
	"testing"

	"github.com/NebulousLabs/Sia/types"
)

// TestIntegrationExplorerFileContractMetrics checks that the siacoin
// transfer volume metric is working correctly.
func TestIntegrationExplorerFileContractMetrics(t *testing.T) {
	if testing.Short() {
		t.Skip()
	}

	et, err := createExplorerTester("TestIntegrationExporerFileContractMetrics")
	if err != nil {
		t.Fatal(err)
	}
	// Propel explorer tester past the hardfork height.
	for i := 0; i < 10; i++ {
		_, err = et.miner.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
	if !et.explorer.activeContractCost.IsZero() {
		t.Error("fresh explorer has nonzero active contract cost")
	}
	if et.explorer.activeContractCount != 0 {
		t.Error("active contract count should initialize to zero")
	}
	if !et.explorer.activeContractSize.IsZero() {
		t.Error("active contract size should initialize to zero")
	}

	// Put a file contract into the chain, and check that the explorer
	// correctly does all of the counting.
	builder := et.wallet.StartTransaction()
	builder.FundSiacoins(types.NewCurrency64(5e9))
	fcOutputs := []types.SiacoinOutput{{Value: types.NewCurrency64(4805e6)}}
	fc := types.FileContract{
		FileSize:           5e3,
		WindowStart:        et.explorer.blockchainHeight + 2,
		WindowEnd:          et.explorer.blockchainHeight + 3,
		Payout:             types.NewCurrency64(5e9),
		ValidProofOutputs:  fcOutputs,
		MissedProofOutputs: fcOutputs,
	}
	_ = builder.AddFileContract(fc)
	txns, err := builder.Sign(true)
	if err != nil {
		t.Fatal(err)
	}
	err = et.tpool.AcceptTransactionSet(txns)
	if err != nil {
		t.Fatal(err)
	}
	_, err = et.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}

	// Check that the stats have updated to represent the file contract.
	if et.explorer.activeContractCost.Cmp(types.NewCurrency64(5e9)) != 0 {
		t.Error("active resources providing wrong file contract cost")
	}
	if et.explorer.activeContractCount != 1 {
		t.Error("active contract count does not read correctly")
	}
	if et.explorer.activeContractSize.Cmp(types.NewCurrency64(5e3)) != 0 {
		t.Error("active contract size is not correctly reported")
	}
	if et.explorer.totalContractCost.Cmp(types.NewCurrency64(5e9)) != 0 {
		t.Error("total cost is not tallied correctly")
	}
	if et.explorer.totalContractCount != 1 {
		t.Error("total contract count is not accurate")
	}
	if et.explorer.totalContractSize.Cmp(types.NewCurrency64(5e3)) != 0 {
		t.Error("total contract size is not accurate")
	}

	// Put a second file into the explorer to check that multiple files are
	// handled well.
	builder = et.wallet.StartTransaction()
	builder.FundSiacoins(types.NewCurrency64(1e9))
	fcOutputs = []types.SiacoinOutput{{Value: types.NewCurrency64(961e6)}}
	fc = types.FileContract{
		FileSize:           15e3,
		WindowStart:        et.explorer.blockchainHeight + 2,
		WindowEnd:          et.explorer.blockchainHeight + 3,
		Payout:             types.NewCurrency64(1e9),
		ValidProofOutputs:  fcOutputs,
		MissedProofOutputs: fcOutputs,
	}
	_ = builder.AddFileContract(fc)
	txns, err = builder.Sign(true)
	if err != nil {
		t.Fatal(err)
	}
	err = et.tpool.AcceptTransactionSet(txns)
	if err != nil {
		t.Fatal(err)
	}
	_, err = et.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}

	// Check that the stats have updated to represent the file contracts.
	if et.explorer.activeContractCost.Cmp(types.NewCurrency64(6e9)) != 0 {
		t.Error("active resources providing wrong file contract cost")
	}
	if et.explorer.activeContractCount != 2 {
		t.Error("active contract count does not read correctly")
	}
	if et.explorer.activeContractSize.Cmp(types.NewCurrency64(20e3)) != 0 {
		t.Error("active contract size is not correctly reported")
	}
	if et.explorer.totalContractCost.Cmp(types.NewCurrency64(6e9)) != 0 {
		t.Error("total cost is not tallied correctly")
	}
	if et.explorer.totalContractCount != 2 {
		t.Error("total contract count is not accurate")
	}
	if et.explorer.totalContractSize.Cmp(types.NewCurrency64(20e3)) != 0 {
		t.Error("total contract size is not accurate")
	}

	// Expire the first file contract but not the second.
	_, err = et.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}

	// Check that the stats have updated to reflect the expired file contract.
	if et.explorer.activeContractCost.Cmp(types.NewCurrency64(1e9)) != 0 {
		t.Error("active resources providing wrong file contract cost", et.explorer.activeContractCost)
	}
	if et.explorer.activeContractCount != 1 {
		t.Error("active contract count does not read correctly")
	}
	if et.explorer.activeContractSize.Cmp(types.NewCurrency64(15e3)) != 0 {
		t.Error("active contract size is not correctly reported")
	}
	if et.explorer.totalContractCost.Cmp(types.NewCurrency64(6e9)) != 0 {
		t.Error("total cost is not tallied correctly")
	}
	if et.explorer.totalContractCount != 2 {
		t.Error("total contract count is not accurate")
	}
	if et.explorer.totalContractSize.Cmp(types.NewCurrency64(20e3)) != 0 {
		t.Error("total contract size is not accurate")
	}

	// TODO: Perform some sort of reorg and check that the reorg is handled
	// correctly.
}
<|endoftext|>


<commit_before>package main

import (
	"net/http/httptest"
	"time"

	. "github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-check"
	"github.com/flynn/flynn/discoverd/testutil"
	"github.com/flynn/flynn/router/client"
	"github.com/flynn/flynn/router/types"
)

func (s *S) newTestAPIServer(t testutil.TestingT) *testAPIServer {
	httpListener := s.newHTTPListener(t)
	tcpListener := s.newTCPListener(t)
	r := &Router{
		HTTP: httpListener,
		TCP:  tcpListener,
	}
	ts := &testAPIServer{
		Server:    httptest.NewServer(apiHandler(r)),
		listeners: []Listener{r.HTTP, r.TCP},
	}

	ts.Client = client.NewWithAddr(ts.Listener.Addr().String())
	return ts
}

type testAPIServer struct {
	client.Client
	*httptest.Server
	listeners []Listener
}

func (s *testAPIServer) Close() error {
	s.Server.Close()
	for _, l := range s.listeners {
		l.Close()
	}
	return nil
}

func (s *S) TestAPIAddTCPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.TCPRoute{Service: "test"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)

	tcpRoute := r.TCPRoute()
	c.Assert(tcpRoute.ID, Not(Equals), "")
	c.Assert(tcpRoute.CreatedAt, Not(IsNil))
	c.Assert(tcpRoute.UpdatedAt, Not(IsNil))
	c.Assert(tcpRoute.Service, Equals, "test")
	c.Assert(tcpRoute.Port, Not(Equals), 0)
	c.Assert(tcpRoute.Leader, Equals, false)

	route, err := srv.GetRoute("tcp", tcpRoute.ID)
	c.Assert(err, IsNil)

	getTCPRoute := route.TCPRoute()
	c.Assert(getTCPRoute.ID, Equals, tcpRoute.ID)
	c.Assert(getTCPRoute.CreatedAt, DeepEquals, tcpRoute.CreatedAt)
	c.Assert(getTCPRoute.UpdatedAt, DeepEquals, tcpRoute.UpdatedAt)
	c.Assert(getTCPRoute.Service, Equals, "test")
	c.Assert(getTCPRoute.Port, Equals, tcpRoute.Port)
	c.Assert(getTCPRoute.Leader, Equals, false)

	err = srv.DeleteRoute("tcp", route.ID)
	c.Assert(err, IsNil)
	_, err = srv.GetRoute("tcp", route.ID)
	c.Assert(err, Equals, client.ErrNotFound)
}

func (s *S) TestAPIAddHTTPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.HTTPRoute{Domain: "example.com", Service: "test"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)

	httpRoute := r.HTTPRoute()
	c.Assert(httpRoute.ID, Not(Equals), "")
	c.Assert(httpRoute.CreatedAt, Not(IsNil))
	c.Assert(httpRoute.UpdatedAt, Not(IsNil))
	c.Assert(httpRoute.Service, Equals, "test")
	c.Assert(httpRoute.Domain, Equals, "example.com")
	c.Assert(httpRoute.Sticky, Equals, false)
	c.Assert(httpRoute.Leader, Equals, false)

	route, err := srv.GetRoute("http", httpRoute.ID)
	c.Assert(err, IsNil)
	c.Assert(httpRoute.ID, Not(Equals), "")

	getHTTPRoute := route.HTTPRoute()
	c.Assert(getHTTPRoute.ID, Equals, httpRoute.ID)
	c.Assert(getHTTPRoute.CreatedAt, DeepEquals, httpRoute.CreatedAt)
	c.Assert(getHTTPRoute.UpdatedAt, DeepEquals, httpRoute.UpdatedAt)
	c.Assert(getHTTPRoute.Service, Equals, "test")
	c.Assert(getHTTPRoute.Domain, Equals, "example.com")
	c.Assert(getHTTPRoute.Sticky, Equals, false)
	c.Assert(getHTTPRoute.Leader, Equals, false)

	err = srv.DeleteRoute("http", route.ID)
	c.Assert(err, IsNil)
	_, err = srv.GetRoute("http", route.ID)
	c.Assert(err, Equals, client.ErrNotFound)
}

func (s *S) TestAPIAddDuplicateRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	// first create route
	r := router.HTTPRoute{Domain: "example.com", Service: "test"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)

	// ensure we got back what we expect
	route := r.HTTPRoute()
	c.Assert(route.ID, Not(Equals), "")
	c.Assert(route.CreatedAt, Not(IsNil))
	c.Assert(route.UpdatedAt, Not(IsNil))
	c.Assert(route.Service, Equals, "test")
	c.Assert(route.Domain, Equals, "example.com")

	// attempt to create the same route again, ensure fails with conflict
	err = srv.CreateRoute(r)
	c.Assert(err, Not(IsNil))
	c.Assert(err.Error(), Equals, "conflict: Duplicate route")

	// delete the route
	err = srv.DeleteRoute("http", route.ID)
	c.Assert(err, IsNil)
	_, err = srv.GetRoute("http", route.ID)
	c.Assert(err, Equals, client.ErrNotFound)
}

func (s *S) TestAPISetHTTPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.HTTPRoute{Domain: "example.com", Service: "foo"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)
	c.Assert(r.ID, Not(IsNil))

	r = router.HTTPRoute{ID: r.ID, Domain: "example.com", Service: "bar", Leader: true, Sticky: true}.ToRoute()
	err = srv.UpdateRoute(r)
	c.Assert(err, IsNil)
	r, err = srv.GetRoute("http", r.ID)
	c.Assert(err, IsNil)
	c.Assert(r.Sticky, Equals, true)
	c.Assert(r.Leader, Equals, true)
	c.Assert(r.Service, Equals, "bar")
}

func (s *S) TestAPISetTCPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.TCPRoute{Service: "foo"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)
	c.Assert(r.ID, Not(IsNil))

	r = router.TCPRoute{ID: r.ID, Service: "bar", Port: int(r.Port), Leader: true}.ToRoute()
	err = srv.UpdateRoute(r)
	c.Assert(err, IsNil)
	r, err = srv.GetRoute("tcp", r.ID)
	c.Assert(err, IsNil)
	c.Assert(r.Leader, Equals, true)
	c.Assert(r.Service, Equals, "bar")
}

func (s *S) TestAPIListRoutes(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r0 := router.HTTPRoute{Domain: "example.com", Service: "test"}.ToRoute()
	r1 := router.HTTPRoute{Domain: "example.net", Service: "test", ParentRef: "foo"}.ToRoute()
	r2 := router.TCPRoute{Service: "test"}.ToRoute()
	r3 := router.TCPRoute{Service: "test", ParentRef: "foo"}.ToRoute()

	err := srv.CreateRoute(r0)
	c.Assert(err, IsNil)
	err = srv.CreateRoute(r1)
	c.Assert(err, IsNil)
	err = srv.CreateRoute(r2)
	c.Assert(err, IsNil)
	err = srv.CreateRoute(r3)
	c.Assert(err, IsNil)

	routes, err := srv.ListRoutes("")
	c.Assert(err, IsNil)
	c.Assert(routes, HasLen, 4)
	c.Assert(routes[3].ID, Equals, r0.ID)
	c.Assert(routes[2].ID, Equals, r1.ID)
	c.Assert(routes[1].ID, Equals, r2.ID)
	c.Assert(routes[0].ID, Equals, r3.ID)

	routes, err = srv.ListRoutes("foo")
	c.Assert(err, IsNil)
	c.Assert(routes, HasLen, 2)
	c.Assert(routes[1].ID, Equals, r1.ID)
	c.Assert(routes[0].ID, Equals, r3.ID)
}

func (s *S) TestStreamEvents(c *C) {
	srv := s.newTestAPIServer(c)
	client := srv.Client
	defer srv.Close()

	l := srv.listeners[0].(*HTTPListener)
	tcpl := srv.listeners[1].(*TCPListener)

	events := make(chan *router.StreamEvent)
	stream, err := client.StreamEvents(events)
	c.Assert(err, IsNil)
	defer stream.Close()

	r := addHTTPRoute(c, l)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "set")
		c.Assert(e.Route.ID, Equals, r.ID)
		c.Assert(e.Route.Type, Equals, "http")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for set event")
	}

	removeRoute(c, l, r.ID)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "remove")
		c.Assert(e.Route.ID, Equals, r.ID)
		c.Assert(e.Route.Type, Equals, "http")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for remove event")
	}

	tcpr := addTCPRoute(c, tcpl, 46000)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "set")
		c.Assert(e.Route.ID, Equals, tcpr.ID)
		c.Assert(e.Route.Type, Equals, "tcp")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for set event")
	}

	removeRoute(c, tcpl, tcpr.ID)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "remove")
		c.Assert(e.Route.ID, Equals, tcpr.ID)
		c.Assert(e.Route.Type, Equals, "tcp")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for remove event")
	}
}
<commit_msg>router: Fix hard-coded high port in tests<commit_after>package main

import (
	"net/http/httptest"
	"time"

	. "github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-check"
	"github.com/flynn/flynn/discoverd/testutil"
	"github.com/flynn/flynn/router/client"
	"github.com/flynn/flynn/router/types"
)

func (s *S) newTestAPIServer(t testutil.TestingT) *testAPIServer {
	httpListener := s.newHTTPListener(t)
	tcpListener := s.newTCPListener(t)
	r := &Router{
		HTTP: httpListener,
		TCP:  tcpListener,
	}
	ts := &testAPIServer{
		Server:    httptest.NewServer(apiHandler(r)),
		listeners: []Listener{r.HTTP, r.TCP},
	}

	ts.Client = client.NewWithAddr(ts.Listener.Addr().String())
	return ts
}

type testAPIServer struct {
	client.Client
	*httptest.Server
	listeners []Listener
}

func (s *testAPIServer) Close() error {
	s.Server.Close()
	for _, l := range s.listeners {
		l.Close()
	}
	return nil
}

func (s *S) TestAPIAddTCPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.TCPRoute{Service: "test"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)

	tcpRoute := r.TCPRoute()
	c.Assert(tcpRoute.ID, Not(Equals), "")
	c.Assert(tcpRoute.CreatedAt, Not(IsNil))
	c.Assert(tcpRoute.UpdatedAt, Not(IsNil))
	c.Assert(tcpRoute.Service, Equals, "test")
	c.Assert(tcpRoute.Port, Not(Equals), 0)
	c.Assert(tcpRoute.Leader, Equals, false)

	route, err := srv.GetRoute("tcp", tcpRoute.ID)
	c.Assert(err, IsNil)

	getTCPRoute := route.TCPRoute()
	c.Assert(getTCPRoute.ID, Equals, tcpRoute.ID)
	c.Assert(getTCPRoute.CreatedAt, DeepEquals, tcpRoute.CreatedAt)
	c.Assert(getTCPRoute.UpdatedAt, DeepEquals, tcpRoute.UpdatedAt)
	c.Assert(getTCPRoute.Service, Equals, "test")
	c.Assert(getTCPRoute.Port, Equals, tcpRoute.Port)
	c.Assert(getTCPRoute.Leader, Equals, false)

	err = srv.DeleteRoute("tcp", route.ID)
	c.Assert(err, IsNil)
	_, err = srv.GetRoute("tcp", route.ID)
	c.Assert(err, Equals, client.ErrNotFound)
}

func (s *S) TestAPIAddHTTPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.HTTPRoute{Domain: "example.com", Service: "test"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)

	httpRoute := r.HTTPRoute()
	c.Assert(httpRoute.ID, Not(Equals), "")
	c.Assert(httpRoute.CreatedAt, Not(IsNil))
	c.Assert(httpRoute.UpdatedAt, Not(IsNil))
	c.Assert(httpRoute.Service, Equals, "test")
	c.Assert(httpRoute.Domain, Equals, "example.com")
	c.Assert(httpRoute.Sticky, Equals, false)
	c.Assert(httpRoute.Leader, Equals, false)

	route, err := srv.GetRoute("http", httpRoute.ID)
	c.Assert(err, IsNil)
	c.Assert(httpRoute.ID, Not(Equals), "")

	getHTTPRoute := route.HTTPRoute()
	c.Assert(getHTTPRoute.ID, Equals, httpRoute.ID)
	c.Assert(getHTTPRoute.CreatedAt, DeepEquals, httpRoute.CreatedAt)
	c.Assert(getHTTPRoute.UpdatedAt, DeepEquals, httpRoute.UpdatedAt)
	c.Assert(getHTTPRoute.Service, Equals, "test")
	c.Assert(getHTTPRoute.Domain, Equals, "example.com")
	c.Assert(getHTTPRoute.Sticky, Equals, false)
	c.Assert(getHTTPRoute.Leader, Equals, false)

	err = srv.DeleteRoute("http", route.ID)
	c.Assert(err, IsNil)
	_, err = srv.GetRoute("http", route.ID)
	c.Assert(err, Equals, client.ErrNotFound)
}

func (s *S) TestAPIAddDuplicateRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	// first create route
	r := router.HTTPRoute{Domain: "example.com", Service: "test"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)

	// ensure we got back what we expect
	route := r.HTTPRoute()
	c.Assert(route.ID, Not(Equals), "")
	c.Assert(route.CreatedAt, Not(IsNil))
	c.Assert(route.UpdatedAt, Not(IsNil))
	c.Assert(route.Service, Equals, "test")
	c.Assert(route.Domain, Equals, "example.com")

	// attempt to create the same route again, ensure fails with conflict
	err = srv.CreateRoute(r)
	c.Assert(err, Not(IsNil))
	c.Assert(err.Error(), Equals, "conflict: Duplicate route")

	// delete the route
	err = srv.DeleteRoute("http", route.ID)
	c.Assert(err, IsNil)
	_, err = srv.GetRoute("http", route.ID)
	c.Assert(err, Equals, client.ErrNotFound)
}

func (s *S) TestAPISetHTTPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.HTTPRoute{Domain: "example.com", Service: "foo"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)
	c.Assert(r.ID, Not(IsNil))

	r = router.HTTPRoute{ID: r.ID, Domain: "example.com", Service: "bar", Leader: true, Sticky: true}.ToRoute()
	err = srv.UpdateRoute(r)
	c.Assert(err, IsNil)
	r, err = srv.GetRoute("http", r.ID)
	c.Assert(err, IsNil)
	c.Assert(r.Sticky, Equals, true)
	c.Assert(r.Leader, Equals, true)
	c.Assert(r.Service, Equals, "bar")
}

func (s *S) TestAPISetTCPRoute(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r := router.TCPRoute{Service: "foo"}.ToRoute()
	err := srv.CreateRoute(r)
	c.Assert(err, IsNil)
	c.Assert(r.ID, Not(IsNil))

	r = router.TCPRoute{ID: r.ID, Service: "bar", Port: int(r.Port), Leader: true}.ToRoute()
	err = srv.UpdateRoute(r)
	c.Assert(err, IsNil)
	r, err = srv.GetRoute("tcp", r.ID)
	c.Assert(err, IsNil)
	c.Assert(r.Leader, Equals, true)
	c.Assert(r.Service, Equals, "bar")
}

func (s *S) TestAPIListRoutes(c *C) {
	srv := s.newTestAPIServer(c)
	defer srv.Close()

	r0 := router.HTTPRoute{Domain: "example.com", Service: "test"}.ToRoute()
	r1 := router.HTTPRoute{Domain: "example.net", Service: "test", ParentRef: "foo"}.ToRoute()
	r2 := router.TCPRoute{Service: "test"}.ToRoute()
	r3 := router.TCPRoute{Service: "test", ParentRef: "foo"}.ToRoute()

	err := srv.CreateRoute(r0)
	c.Assert(err, IsNil)
	err = srv.CreateRoute(r1)
	c.Assert(err, IsNil)
	err = srv.CreateRoute(r2)
	c.Assert(err, IsNil)
	err = srv.CreateRoute(r3)
	c.Assert(err, IsNil)

	routes, err := srv.ListRoutes("")
	c.Assert(err, IsNil)
	c.Assert(routes, HasLen, 4)
	c.Assert(routes[3].ID, Equals, r0.ID)
	c.Assert(routes[2].ID, Equals, r1.ID)
	c.Assert(routes[1].ID, Equals, r2.ID)
	c.Assert(routes[0].ID, Equals, r3.ID)

	routes, err = srv.ListRoutes("foo")
	c.Assert(err, IsNil)
	c.Assert(routes, HasLen, 2)
	c.Assert(routes[1].ID, Equals, r1.ID)
	c.Assert(routes[0].ID, Equals, r3.ID)
}

func (s *S) TestStreamEvents(c *C) {
	srv := s.newTestAPIServer(c)
	client := srv.Client
	defer srv.Close()

	l := srv.listeners[0].(*HTTPListener)
	tcpl := srv.listeners[1].(*TCPListener)

	events := make(chan *router.StreamEvent)
	stream, err := client.StreamEvents(events)
	c.Assert(err, IsNil)
	defer stream.Close()

	r := addHTTPRoute(c, l)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "set")
		c.Assert(e.Route.ID, Equals, r.ID)
		c.Assert(e.Route.Type, Equals, "http")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for set event")
	}

	removeRoute(c, l, r.ID)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "remove")
		c.Assert(e.Route.ID, Equals, r.ID)
		c.Assert(e.Route.Type, Equals, "http")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for remove event")
	}

	tcpr := addTCPRoute(c, tcpl, allocatePort())
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "set")
		c.Assert(e.Route.ID, Equals, tcpr.ID)
		c.Assert(e.Route.Type, Equals, "tcp")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for set event")
	}

	removeRoute(c, tcpl, tcpr.ID)
	select {
	case e, ok := <-events:
		if !ok {
			c.Fatal("unexpected close of event stream")
		}
		c.Assert(e.Event, Equals, "remove")
		c.Assert(e.Route.ID, Equals, tcpr.ID)
		c.Assert(e.Route.Type, Equals, "tcp")
		c.Assert(e.Error, IsNil)
	case <-time.After(10 * time.Second):
		c.Fatal("Timed out waiting for remove event")
	}
}
<|endoftext|>


<commit_before>package lidar

import (
	"errors"
	"log"
	"time"

	"github.com/dasfoo/i2c"
)

// TODO: ADD Mutex
// TODO Check grammar

// Lidar is structure to access basic functions of LidarLite
// LidarLite_V2 blue label
// Model LL-905-PIN-02
// Documentation on http://lidarlite.com/docs/v2/specs_and_hardware
type Lidar struct {
	bus            *i2c.Bus
	address        byte
	continuousMode bool
}

// MaxAttemptNumber - maximum number of attempts to do operation
const MaxAttemptNumber = 50

const (
	// NotReady - Ready status. 0 - ready for a new command, 1 - busy
	// with acquisition.
	NotReady = 1 << iota

	// RefOverflow - Overflow detected in correlation process assotieted with
	// a reference acquisition. Signal overflow flag and Reference overflow flag
	// are set when automatic limiting occurs.
	RefOverflow = 1 << iota

	// SignalOverflow - Overflow detected in correlation process assotieted with a signal
	// acquisition
	SignalOverflow = 1 << iota

	// SignalNotValid - Indicates that the signal correlation peak is equal to or below
	// correlation record threshold
	SignalNotValid = 1 << iota

	// SecondaryReturn - Secondary return detected above correlation noise floor threshold
	SecondaryReturn = 1 << iota

	// Health - 1 if is good, 0 if is bad
	Health = 1 << iota

	// ErrorDetection - Process error detected/measurement invalid
	ErrorDetection = 1 << iota

	// EyeSafe - This bit will go high if eye-safety protection has been activated
	EyeSafe = 1 << iota
)

// NewLidar sets the configuration for the sensor and return all registers in
// default values before using
func NewLidar(i2cbus, addr byte) *Lidar {
	bus, err := i2c.NewBus(i2cbus)
	if err != nil {
		log.Panic(err)
	}
	lSensor := Lidar{
		bus:            bus,
		address:        addr,
		continuousMode: false,
	}
	lSensor.Reset()
	log.Println("Initialization is done")
	return &lSensor
}

// Reset writes 0x00 to Register 0x00 reset FPGA. Re-loads FPGA from internal Flash
// memory: all registers return to default values
// During initialization the microcontroller goes *throw* a self-test followed by
// initialization of the internal control registers with default values. After that
// processor goes into sleep state reducing overall power consumption to under
// 10 mA. Initiation of a user command, throw external trigger or I2C command,
// awakes a processor allowing subsequent opetation.
func (ls *Lidar) Reset() {
	if e := ls.bus.WriteByteToReg(ls.address, 0x00, 0x00); e != nil {
		log.Panic("Write ", e)
	}
	time.Sleep(1 * time.Second) // TODO: remove if it is possible
}

// Read reads from the register and the same time check status of controller.
// If Status is bad or error was detectec, it tries again
func (ls *Lidar) Read(register byte) (byte, error) {
	for i := 0; i < MaxAttemptNumber; i++ {
		st, errSt := ls.GetStatus()
		switch {
		case errSt != nil:
			log.Println(errSt)
		case st&Health == 0:
			log.Println("Bad Health of controller")
			val, rErr := ls.bus.ReadByteFromReg(ls.address, register)
			if rErr == nil {
				return val, nil
			}
		case st&ErrorDetection != 0:
			log.Println("Error detected")
		case st&SignalOverflow == 0:
			log.Println("Automatic limiting doesn't occurs ")
		default:
			val, rErr := ls.bus.ReadByteFromReg(ls.address, register)
			if rErr == nil {
				return val, nil
			}
		}
		//if ask Status often, Health status is bad
		time.Sleep(1 * time.Second)
	}
	return 0, errors.New("Read limit occurs")
}

// WriteByteToRegister - write value(byte) to register
// Read register 0x01(this is handled in the GetStatus() command)
// if sensor is NotReady for new command, loop tries again until MaxAttemptNumber
// occurs or sensor is ready
func (ls *Lidar) WriteByteToRegister(register, value byte) error {
	for i := 0; i < MaxAttemptNumber; i++ {
		st, errSt := ls.GetStatus()
		switch {
		case errSt != nil:
			log.Println(errSt)
		case st&NotReady != 0:
			log.Println("Not ready to start new command")
		default:
			return ls.bus.WriteByteToReg(ls.address, register, value)
		}
		time.Sleep(1 * time.Second)
	}
	return errors.New("Write limit occurs")
}

// Close closes releases the resources associated with the bus
func (ls *Lidar) Close() {
	// Reset FPGA. All registers return to default values
	ls.Reset()
	if err := ls.bus.Close(); err != nil {
		log.Println(err)
	}
	log.Println("Closing sensor is done")
}

// GetStatus gets Mode/Status of sensor
func (ls *Lidar) GetStatus() (byte, error) {
	val, err := ls.bus.ReadByteFromReg(ls.address, 0x01)
	if err != nil {
		log.Println("GetStatus", err)
		return 0, err
	}
	log.Printf("Status: %.8b\n", val)
	return val, nil
}

// Distance reads the distance from LidarLite
// stablizePreampFlag - true - take aquisition with DC stabilisation/correction.
// false - it will read faster, but you will need to stabilize DC every once in
// awhile(ex. 1 out of every 100 readings is typically good)
// Autoincrement: A note about 0x8f vs 0x0f
// Set the highest bit of any register to "1" if you set the high byte of a
// register and then take succesive readings from that register, then LIDAR-
// Lite automatically increments the register one for each read. An example: If
// we want to read the high and low bytes for the distance, we could take two
// single readings from 0x0f and 0x10, or we could take 2 byte read from reg-
// ister 0x8f. 0x8f = 10001111 and 0x0f = 00001111, meaning that 0x8f is 0x0f
// with the high byte set to "1", ergo it autoincrements.
func (ls *Lidar) Distance(stablizePreampFlag bool) (int, error) {
	if !ls.continuousMode {
		var wErr error // Write error
		if stablizePreampFlag {
			wErr = ls.WriteByteToRegister(0x00, 0x04)
		} else {
			wErr = ls.WriteByteToRegister(0x00, 0x03)
		}
		if wErr != nil {
			log.Println("Write ", wErr)
			return -1, wErr
		}
		// The total acquisition time for the reference and signal acquisition is
		// typically between 5 and 20 ms depending on the desired number of integrated
		// pulses and the length of the correlation record. The acquisition time
		// plus the required 1 msec to download measurement parameters establish a
		// a roughly 100Hz maximum measurement rate.
		time.Sleep(250 * time.Millisecond)
	}
	return ls.distanceContinuous()
}

// Velocity is measured by observing the change in distance over a fixed time
// of period
// It reads in 0.1 meters/sec. See Mode Control, Register 0x04 for information
// on changing the scale factor to 1m/sec
// TODO 0x04 Check Mode Control
func (ls *Lidar) Velocity() (int, error) {
	// Write 0xa0 to 0x04 to switch on velocity mode
	// Before changing mode we need to check status
	log.Println("Starting velocity mode") //
	if wErr := ls.WriteByteToRegister(0x04, 0xa0); wErr != nil {
		log.Println("Write ", wErr)
		return -1, wErr
	}

	// Write 0x04 to register 0x00 to start getting distance readings
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x00, 0x04); wErr != nil {
		log.Println("Write ", wErr)
		return -1, wErr
	}
	log.Println("Velocity  reading....")

	//Read 1 byte from register 0x09 to get velocity measurement
	val, e := ls.Read(0x09)
	if e != nil {
		log.Println(e)
		return -1, e
	}
	return int(val), nil
}

// BeginContinuous allows to tell the sensor to take a certain number of (or
// infinite) readings allowing you to read from it at a continuous rate.
// - modePinLow - tells the mode pin to go low when a new reading is available. TODO:Test it.
// - interval - set the time between measurements, default is 0x04. TODO Add time.Duration
//   0xc8 corresponds to 10Hz while 0x13 corresponds to 100Hz. Maximum
//   value is 0x02 for proper operations
// - numberOfReadings - set the number of readings to take before stopping
//   0xfe = 254 readings, 0x01 = 1 reading and 0xff = continuous readings
//   A value of less than 0xff will terminate continuous measurement after that
//   amount of measurements(ex. 0xfe will take 254 measurements and stop)(from
//   documentation-www.lidarlite.com/docs/v2/registers/. But practically it
//   doesn't work, it continues to count
func (ls *Lidar) BeginContinuous(modePinLow bool, interval, numberOfReadings byte) error {
	// Register 0x45 sets the time between measurements. Min val os 0x02
	// for proper operations.
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x45, interval); wErr != nil {
		log.Println(wErr)
		return wErr
	}
	var byteToReg byte
	byteToReg = 0x20
	if modePinLow {
		byteToReg = 0x21
	}
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x04, byteToReg); wErr != nil {
		log.Print(wErr)
		return wErr
	}
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x11, numberOfReadings); wErr != nil {
		log.Println(wErr)
		return wErr
	}

	// Initiate reading distance
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x00, 0x04); wErr != nil {
		log.Println(wErr)
		return wErr
	}

	log.Println("Continuous mode has started...")
	ls.continuousMode = true
	time.Sleep(1 * time.Second) // Time is to do acquisition before reading
	return nil
}

// StopContinuous stops continuous mode and sensor is ready to get new command,
// for ex. distance of velocity mode. This method returns to default values.
func (ls *Lidar) StopContinuous() {
	ls.Reset()
	ls.continuousMode = false
	log.Println("Continuous mode has stopped")
}

// TODO rename function
// distanceContinuous reads in continuous mode
func (ls *Lidar) distanceContinuous() (int, error) {

	status, err := ls.GetStatus()
	switch {
	case err != nil:
		log.Println(err)
		return -1, err
	case status&Health == 0:
		val, rErr := ls.bus.ReadWordFromReg(ls.address, 0x8f)
		log.Println("Bad health of sensor")
		if rErr != nil {
			log.Println("Read", rErr)
			return -1, rErr
		}
		return int(val), nil
	case status&ErrorDetection != 0:
		return -1, errors.New("Error in counting detected")
	case status&SignalOverflow == 0:
		return -1, errors.New("Automatic limiting doesn't occurs")
	default:
		val, rErr := ls.bus.ReadWordFromReg(ls.address, 0x8f)
		if rErr != nil {
			log.Println("Read", rErr)
			return -1, rErr
		}
		return int(val), nil
	}
}
<commit_msg>Rename distanceContinuous to readDistance<commit_after>package lidar

import (
	"errors"
	"log"
	"time"

	"github.com/dasfoo/i2c"
)

// TODO: ADD Mutex
// TODO Check grammar

// Lidar is structure to access basic functions of LidarLite
// LidarLite_V2 blue label
// Model LL-905-PIN-02
// Documentation on http://lidarlite.com/docs/v2/specs_and_hardware
type Lidar struct {
	bus            *i2c.Bus
	address        byte
	continuousMode bool
}

// MaxAttemptNumber - maximum number of attempts to do operation
const MaxAttemptNumber = 50

const (
	// NotReady - Ready status. 0 - ready for a new command, 1 - busy
	// with acquisition.
	NotReady = 1 << iota

	// RefOverflow - Overflow detected in correlation process assotieted with
	// a reference acquisition. Signal overflow flag and Reference overflow flag
	// are set when automatic limiting occurs.
	RefOverflow = 1 << iota

	// SignalOverflow - Overflow detected in correlation process assotieted with a signal
	// acquisition
	SignalOverflow = 1 << iota

	// SignalNotValid - Indicates that the signal correlation peak is equal to or below
	// correlation record threshold
	SignalNotValid = 1 << iota

	// SecondaryReturn - Secondary return detected above correlation noise floor threshold
	SecondaryReturn = 1 << iota

	// Health - 1 if is good, 0 if is bad
	Health = 1 << iota

	// ErrorDetection - Process error detected/measurement invalid
	ErrorDetection = 1 << iota

	// EyeSafe - This bit will go high if eye-safety protection has been activated
	EyeSafe = 1 << iota
)

// NewLidar sets the configuration for the sensor and return all registers in
// default values before using
func NewLidar(i2cbus, addr byte) *Lidar {
	bus, err := i2c.NewBus(i2cbus)
	if err != nil {
		log.Panic(err)
	}
	lSensor := Lidar{
		bus:            bus,
		address:        addr,
		continuousMode: false,
	}
	lSensor.Reset()
	log.Println("Initialization is done")
	return &lSensor
}

// Reset writes 0x00 to Register 0x00 reset FPGA. Re-loads FPGA from internal Flash
// memory: all registers return to default values
// During initialization the microcontroller goes *throw* a self-test followed by
// initialization of the internal control registers with default values. After that
// processor goes into sleep state reducing overall power consumption to under
// 10 mA. Initiation of a user command, throw external trigger or I2C command,
// awakes a processor allowing subsequent opetation.
func (ls *Lidar) Reset() {
	if e := ls.bus.WriteByteToReg(ls.address, 0x00, 0x00); e != nil {
		log.Panic("Write ", e)
	}
	time.Sleep(1 * time.Second) // TODO: remove if it is possible
}

// Read reads from the register and the same time check status of controller.
// If Status is bad or error was detected, it tries again
func (ls *Lidar) Read(register byte) (byte, error) {
	for i := 0; i < MaxAttemptNumber; i++ {
		st, errSt := ls.GetStatus()
		switch {
		case errSt != nil:
			log.Println(errSt)
		case st&Health == 0:
			log.Println("Bad Health of controller")
			val, rErr := ls.bus.ReadByteFromReg(ls.address, register)
			if rErr == nil {
				return val, nil
			}
		case st&ErrorDetection != 0:
			log.Println("Error detected")
		case st&SignalOverflow == 0:
			log.Println("Automatic limiting doesn't occurs ")
		default:
			val, rErr := ls.bus.ReadByteFromReg(ls.address, register)
			if rErr == nil {
				return val, nil
			}
		}
		//if ask Status often, Health status is bad
		time.Sleep(1 * time.Second)
	}
	return 0, errors.New("Read limit occurs")
}

// WriteByteToRegister - write value(byte) to register
// Read register 0x01(this is handled in the GetStatus() command)
// if sensor is NotReady for new command, loop tries again until MaxAttemptNumber
// occurs or sensor is ready
func (ls *Lidar) WriteByteToRegister(register, value byte) error {
	for i := 0; i < MaxAttemptNumber; i++ {
		st, errSt := ls.GetStatus()
		switch {
		case errSt != nil:
			log.Println(errSt)
		case st&NotReady != 0:
			log.Println("Not ready to start new command")
		default:
			return ls.bus.WriteByteToReg(ls.address, register, value)
		}
		time.Sleep(1 * time.Second)
	}
	return errors.New("Write limit occurs")
}

// Close closes releases the resources associated with the bus
func (ls *Lidar) Close() {
	// Reset FPGA. All registers return to default values
	ls.Reset()
	if err := ls.bus.Close(); err != nil {
		log.Println(err)
	}
	log.Println("Closing sensor is done")
}

// GetStatus gets Mode/Status of sensor
func (ls *Lidar) GetStatus() (byte, error) {
	val, err := ls.bus.ReadByteFromReg(ls.address, 0x01)
	if err != nil {
		log.Println("GetStatus", err)
		return 0, err
	}
	log.Printf("Status: %.8b\n", val)
	return val, nil
}

// Distance reads the distance from LidarLite
// stablizePreampFlag - true - take aquisition with DC stabilisation/correction.//TODO read more
// false - it will read faster, but you will need to stabilize DC every once in
// awhile(ex. 1 out of every 100 readings is typically good)
// Autoincrement: A note about 0x8f vs 0x0f
// Set the highest bit of any register to "1" if you set the high byte of a
// register and then take succesive readings from that register, then LIDAR-
// Lite automatically increments the register one for each read. An example: If
// we want to read the high and low bytes for the distance, we could take two
// single readings from 0x0f and 0x10, or we could take 2 byte read from reg-
// ister 0x8f. 0x8f = 10001111 and 0x0f = 00001111, meaning that 0x8f is 0x0f
// with the high byte set to "1", ergo it autoincrements.
func (ls *Lidar) Distance(stablizePreampFlag bool) (int, error) {
	if !ls.continuousMode {
		var wErr error // Write error
		if stablizePreampFlag {
			wErr = ls.WriteByteToRegister(0x00, 0x04)
		} else {
			wErr = ls.WriteByteToRegister(0x00, 0x03)
		}
		if wErr != nil {
			log.Println("Write ", wErr)
			return -1, wErr
		}
		// The total acquisition time for the reference and signal acquisition is
		// typically between 5 and 20 ms depending on the desired number of integrated
		// pulses and the length of the correlation record. The acquisition time
		// plus the required 1 msec to download measurement parameters establish a
		// a roughly 100Hz maximum measurement rate.
		time.Sleep(250 * time.Millisecond)
	}
	return ls.readDistance()
}

// Velocity is measured by observing the change in distance over a fixed time
// of period
// It reads in 0.1 meters/sec. See Mode Control, Register 0x04 for information
// on changing the scale factor to 1m/sec
// TODO 0x04 Check Mode Control
func (ls *Lidar) Velocity() (int, error) {
	// Write 0xa0 to 0x04 to switch on velocity mode
	// Before changing mode we need to check status
	log.Println("Starting velocity mode") //
	if wErr := ls.WriteByteToRegister(0x04, 0xa0); wErr != nil {
		log.Println("Write ", wErr)
		return -1, wErr
	}

	// Write 0x04 to register 0x00 to start getting distance readings
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x00, 0x04); wErr != nil {
		log.Println("Write ", wErr)
		return -1, wErr
	}
	log.Println("Velocity  reading....")

	//Read 1 byte from register 0x09 to get velocity measurement
	val, e := ls.Read(0x09)
	if e != nil {
		log.Println(e)
		return -1, e
	}
	return int(val), nil
}

// BeginContinuous allows to tell the sensor to take a certain number of (or
// infinite) readings allowing you to read from it at a continuous rate.
// - modePinLow - tells the mode pin to go low when a new reading is available. TODO:Test it.
// - interval - set the time between measurements, default is 0x04. TODO Add time.Duration
//   0xc8 corresponds to 10Hz while 0x13 corresponds to 100Hz. Minimum
//   value is 0x02 for proper operations
// - numberOfReadings - set the number of readings to take before stopping
//   0xfe = 254 readings, 0x01 = 1 reading and 0xff = continuous readings
//   A value of less than 0xff will terminate continuous measurement after that
//   amount of measurements(ex. 0xfe will take 254 measurements and stop)(from
//   documentation-www.lidarlite.com/docs/v2/registers/. But practically it
//   doesn't work, it continues to count
func (ls *Lidar) BeginContinuous(modePinLow bool, interval, numberOfReadings byte) error {
	// Register 0x45 sets the time between measurements. Min value is 0x02
	// for proper operations.
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x45, interval); wErr != nil {
		log.Println(wErr)
		return wErr
	}
	var byteToReg byte
	byteToReg = 0x20
	if modePinLow {
		byteToReg = 0x21
	}
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x04, byteToReg); wErr != nil {
		log.Print(wErr)
		return wErr
	}
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x11, numberOfReadings); wErr != nil {
		log.Println(wErr)
		return wErr
	}

	// Initiate reading distance
	if wErr := ls.bus.WriteByteToReg(ls.address, 0x00, 0x04); wErr != nil {
		log.Println(wErr)
		return wErr
	}

	log.Println("Continuous mode has started...")
	ls.continuousMode = true
	time.Sleep(1 * time.Second) // Time is to do acquisition before reading
	return nil
}

// StopContinuous stops continuous mode and sensor is ready to get new command,
// for ex. distance of velocity mode. This method returns to default values.
func (ls *Lidar) StopContinuous() {
	ls.Reset()
	ls.continuousMode = false
	log.Println("Continuous mode has stopped")
}

// readDistance reads distance in any mode
func (ls *Lidar) readDistance() (int, error) {

	status, err := ls.GetStatus()
	switch {
	case err != nil:
		log.Println(err)
		return -1, err
	case status&Health == 0:
		val, rErr := ls.bus.ReadWordFromReg(ls.address, 0x8f)
		log.Println("Bad health of sensor")
		if rErr != nil {
			log.Println("Read", rErr)
			return -1, rErr
		}
		return int(val), nil
	case status&ErrorDetection != 0:
		return -1, errors.New("Error in counting detected")
	case status&SignalOverflow == 0:
		return -1, errors.New("Automatic limiting doesn't occurs")
	default:
		val, rErr := ls.bus.ReadWordFromReg(ls.address, 0x8f)
		if rErr != nil {
			log.Println("Read", rErr)
			return -1, rErr
		}
		return int(val), nil
	}
}
<|endoftext|>


<commit_before>package newsCache

import (
	"fmt"
	"strings"
	"time"
	"web_apps/news_crawlers/modules/database"

	"gopkg.in/mgo.v2/bson"
)

var (
	newsIndexKeySlice = []string{"index", "ids"}
	newsIndexIDS      []bson.ObjectId
)

// NewsIndexCache make an index news for fast access
func NewsIndexCache(stop chan bool) {
	fmt.Println("starting news index cache...")

	result, err := database.NewsIndexNewsIDS()
	if err != nil {
		return
	}

	pushIDredis(result...)
}

func pushIDredis(IDS ...database.NewsIds) {
	start := time.Now()
	conn := database.RedisPool.Get()
	defer conn.Close()

	key := RedisKeyGen(newsIndexKeySlice...)
	var strID []string
	for _, item := range IDS {
		strID = append(strID, item.ID.Hex())
	}

	// DELETE existing
	conn.Send("DEL", key)

	for _, id := range strID {
		conn.Send("LPUSH", key, id)
	}
	conn.Flush()
	res, err := conn.Receive()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("push to cache index took: ", time.Since(start), "and redis: ", res)
}

// DeleteKey remove keys from redis
func DeleteKey(keys ...string) {
	conn := database.RedisPool.Get()
	defer conn.Close()

	for _, key := range keys {
		_, err := conn.Do("DEL", key)
		if err != nil {
			fmt.Println(err)
			return
		}
	}
}

// RedisKeyGen generate redis keys based on slice
func RedisKeyGen(keys ...string) string {
	return strings.Join(keys, ":")
}
<commit_msg>update added reverse keys<commit_after>package newsCache

import (
	"fmt"
	"sort"
	"strings"
	"time"
	"web_apps/news_crawlers/modules/database"

	"gopkg.in/mgo.v2/bson"
)

var (
	newsIndexKeySlice = []string{"index", "ids"}
	newsIndexIDS      []bson.ObjectId
)

// NewsIndexCache make an index news for fast access
func NewsIndexCache(stop chan bool) {
	fmt.Println("starting news index cache...")

	result, err := database.NewsIndexNewsIDS()
	if err != nil {
		return
	}

	pushIDredis(result...)
}

func pushIDredis(IDS ...database.NewsIds) {
	start := time.Now()
	conn := database.RedisPool.Get()
	defer conn.Close()

	key := RedisKeyGen(newsIndexKeySlice...)
	var strID []string
	for _, item := range IDS {
		strID = append(strID, item.ID.Hex())
	}

	sort.Sort(sort.Reverse(sort.StringSlice(strID)))
	// DELETE existing
	conn.Send("DEL", key)

	for _, id := range strID {
		conn.Send("RPUSH", key, id)
	}
	conn.Flush()
	res, err := conn.Receive()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("push to cache index took: ", time.Since(start), "and redis: ", res)
}

// DeleteKey remove keys from redis
func DeleteKey(keys ...string) {
	conn := database.RedisPool.Get()
	defer conn.Close()

	for _, key := range keys {
		_, err := conn.Do("DEL", key)
		if err != nil {
			fmt.Println(err)
			return
		}
	}
}

// RedisKeyGen generate redis keys based on slice
func RedisKeyGen(keys ...string) string {
	return strings.Join(keys, ":")
}
<|endoftext|>


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

// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package rsets

import (
	"fmt"
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/context"
	"github.com/pingcap/tidb/expression"
	"github.com/pingcap/tidb/field"
	"github.com/pingcap/tidb/plan"
	"github.com/pingcap/tidb/plan/plans"
	"github.com/pingcap/tidb/stmt"
	"github.com/pingcap/tidb/table"
)

var (
	_ plan.Planner = (*JoinRset)(nil)
)

// JoinType is join type, including cross/left/right/full.
type JoinType int

// String gets string value of join type.
func (t JoinType) String() string {
	switch t {
	case CrossJoin:
		return plans.CrossJoin
	case LeftJoin:
		return plans.LeftJoin
	case RightJoin:
		return plans.RightJoin
	case FullJoin:
		return plans.FullJoin
	}

	return "Unknown"
}

const (
	// CrossJoin is cross join type.
	CrossJoin JoinType = iota + 1
	// LeftJoin is left Join type.
	LeftJoin
	// RightJoin is right Join type.
	RightJoin
	// FullJoin is full Join type.
	FullJoin
)

// JoinRset is record set for table join.
type JoinRset struct {
	Left  interface{}
	Right interface{}
	Type  JoinType
	On    expression.Expression

	tableNames map[string]bool
}

func (r *JoinRset) String() string {
	left := r.formatNode(r.Left)

	if r.Right == nil {
		return left
	}

	onStr := ""
	if r.On != nil {
		onStr = fmt.Sprintf(" ON %s", r.On.String())
	}

	right := r.formatNode(r.Right)
	return fmt.Sprintf("%v %s JOIN %v%s", left, r.Type, right, onStr)
}

func (r *JoinRset) formatNode(node interface{}) string {
	switch x := node.(type) {
	case *TableSource:
		return x.String()
	case *JoinRset:
		return fmt.Sprintf("(%s)", x.String())
	}

	panic(fmt.Sprintf("invalid join source %T", node))
}

func (r *JoinRset) buildJoinPlan(ctx context.Context, p *plans.JoinPlan, s *JoinRset) error {
	left, leftFields, err := r.buildPlan(ctx, s.Left)
	if err != nil {
		return errors.Trace(err)
	}

	right, rightFields, err := r.buildPlan(ctx, s.Right)
	if err != nil {
		return errors.Trace(err)
	}

	p.Left = left
	p.Right = right
	p.On = s.On
	p.Type = s.Type.String()

	// if the left is not JoinPlan, the left is the leaf node,
	// we can stop recursion.
	if pl, ok := left.(*plans.JoinPlan); ok {
		if err := r.buildJoinPlan(ctx, pl, s.Left.(*JoinRset)); err != nil {
			return errors.Trace(err)
		}

		// use left JoinPlan fields.
		p.Fields = append(p.Fields, pl.GetFields()...)
	} else {
		// use left fields directly.
		p.Fields = append(p.Fields, leftFields...)
	}

	// if the right is not JoinPlan, the right is the leaf node,
	// we can stop recursion.
	if pr, ok := right.(*plans.JoinPlan); ok {
		if err := r.buildJoinPlan(ctx, pr, s.Right.(*JoinRset)); err != nil {
			return errors.Trace(err)
		}
		// use right JoinPlan fields.
		p.Fields = append(p.Fields, pr.GetFields()...)
	} else {
		// use right fields directly.
		p.Fields = append(p.Fields, rightFields...)
	}

	return nil
}

func (r *JoinRset) buildPlan(ctx context.Context, node interface{}) (plan.Plan, []*field.ResultField, error) {
	switch t := node.(type) {
	case *JoinRset:
		return &plans.JoinPlan{}, nil, nil
	case *TableSource:
		return r.buildSourcePlan(ctx, t)
	case nil:
		return nil, nil, nil
	default:
		return nil, nil, errors.Errorf("invalid join node %T", t)
	}
}

func (r *JoinRset) checkTableDuplicate(t *TableSource, tr *TableRset) error {
	if len(t.Name) > 0 {
		// use alias name
		_, ok := r.tableNames[t.Name]
		if ok {
			return errors.Errorf("%s: duplicate name %s", r, t.Name)
		}
		r.tableNames[t.Name] = true
		return nil
	}

	// first check ident name
	identName := t.String()
	_, ok := r.tableNames[identName]
	if ok {
		return errors.Errorf("%s: duplicate name %s", r, identName)
	}
	r.tableNames[identName] = true

	qualifedName := tr.Schema + "." + tr.Name
	// we should check qualifed name too, e,g select * form t1 join test.t1
	if identName != qualifedName {
		_, ok = r.tableNames[qualifedName]
		if ok {
			return errors.Errorf("%s: duplicate name %s", r, t.String())
		}
		r.tableNames[qualifedName] = true
	}

	return nil
}

func (r *JoinRset) buildSourcePlan(ctx context.Context, t *TableSource) (plan.Plan, []*field.ResultField, error) {
	var (
		src interface{}
		tr  *TableRset
		err error
	)
	switch s := t.Source.(type) {
	case table.Ident:
		fullIdent := s.Full(ctx)
		tr, err = newTableRset(fullIdent.Schema.O, fullIdent.Name.O)
		if err != nil {
			return nil, nil, errors.Trace(err)
		}
		src = tr
		if err := r.checkTableDuplicate(t, tr); err != nil {
			return nil, nil, errors.Trace(err)
		}
	case stmt.Statement:
		src = s
	default:
		return nil, nil, errors.Errorf("invalid table source %T", t.Source)
	}

	var p plan.Plan
	switch x := src.(type) {
	case plan.Planner:
		if p, err = x.Plan(ctx); err != nil {
			return nil, nil, errors.Trace(err)
		}
	case plan.Plan:
		p = x
	default:
		return nil, nil, errors.Errorf("invalid table source %T, no Plan interface", t.Source)
	}

	var fields []*field.ResultField
	dupNames := make(map[string]struct{}, len(p.GetFields()))
	for _, nf := range p.GetFields() {
		f := nf.Clone()
		if t.Name != "" {
			f.TableName = t.Name
		}

		// duplicate column name in one table is not allowed.
		name := strings.ToLower(f.Name)
		if _, ok := dupNames[name]; ok {
			return nil, nil, errors.Errorf("Duplicate column name '%s'", name)
		}
		dupNames[name] = struct{}{}

		fields = append(fields, f)
	}

	return p, fields, nil
}

// Plan gets JoinPlan.
func (r *JoinRset) Plan(ctx context.Context) (plan.Plan, error) {
	r.tableNames = make(map[string]bool)
	p := &plans.JoinPlan{}
	if err := r.buildJoinPlan(ctx, p, r); err != nil {
		return nil, errors.Trace(err)
	}

	return p, nil
}

// MultipleTable checks if the JoinRset contains multiple tables.
func (r *JoinRset) MultipleTable() bool {
	if _, ok := r.Left.(*TableSource); ok {
		if r.Right == nil {
			return false
		}
	}
	return true
}
<commit_msg>rsets: Address comment<commit_after>// Copyright 2014 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSES/QL-LICENSE file.

// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package rsets

import (
	"fmt"
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/context"
	"github.com/pingcap/tidb/expression"
	"github.com/pingcap/tidb/field"
	"github.com/pingcap/tidb/plan"
	"github.com/pingcap/tidb/plan/plans"
	"github.com/pingcap/tidb/stmt"
	"github.com/pingcap/tidb/table"
)

var (
	_ plan.Planner = (*JoinRset)(nil)
)

// JoinType is join type, including cross/left/right/full.
type JoinType int

// String gets string value of join type.
func (t JoinType) String() string {
	switch t {
	case CrossJoin:
		return plans.CrossJoin
	case LeftJoin:
		return plans.LeftJoin
	case RightJoin:
		return plans.RightJoin
	case FullJoin:
		return plans.FullJoin
	}

	return "Unknown"
}

const (
	// CrossJoin is cross join type.
	CrossJoin JoinType = iota + 1
	// LeftJoin is left Join type.
	LeftJoin
	// RightJoin is right Join type.
	RightJoin
	// FullJoin is full Join type.
	FullJoin
)

// JoinRset is record set for table join.
type JoinRset struct {
	Left  interface{}
	Right interface{}
	Type  JoinType
	On    expression.Expression

	tableNames map[string]bool
}

func (r *JoinRset) String() string {
	left := r.formatNode(r.Left)

	if r.Right == nil {
		return left
	}

	onStr := ""
	if r.On != nil {
		onStr = fmt.Sprintf(" ON %s", r.On.String())
	}

	right := r.formatNode(r.Right)
	return fmt.Sprintf("%v %s JOIN %v%s", left, r.Type, right, onStr)
}

func (r *JoinRset) formatNode(node interface{}) string {
	switch x := node.(type) {
	case *TableSource:
		return x.String()
	case *JoinRset:
		return fmt.Sprintf("(%s)", x.String())
	}

	panic(fmt.Sprintf("invalid join source %T", node))
}

func (r *JoinRset) buildJoinPlan(ctx context.Context, p *plans.JoinPlan, s *JoinRset) error {
	left, leftFields, err := r.buildPlan(ctx, s.Left)
	if err != nil {
		return errors.Trace(err)
	}

	right, rightFields, err := r.buildPlan(ctx, s.Right)
	if err != nil {
		return errors.Trace(err)
	}

	p.Left = left
	p.Right = right
	p.On = s.On
	p.Type = s.Type.String()

	// if the left is not JoinPlan, the left is the leaf node,
	// we can stop recursion.
	if pl, ok := left.(*plans.JoinPlan); ok {
		if err := r.buildJoinPlan(ctx, pl, s.Left.(*JoinRset)); err != nil {
			return errors.Trace(err)
		}

		// use left JoinPlan fields.
		p.Fields = append(p.Fields, pl.GetFields()...)
	} else {
		// use left fields directly.
		p.Fields = append(p.Fields, leftFields...)
	}

	// if the right is not JoinPlan, the right is the leaf node,
	// we can stop recursion.
	if pr, ok := right.(*plans.JoinPlan); ok {
		if err := r.buildJoinPlan(ctx, pr, s.Right.(*JoinRset)); err != nil {
			return errors.Trace(err)
		}
		// use right JoinPlan fields.
		p.Fields = append(p.Fields, pr.GetFields()...)
	} else {
		// use right fields directly.
		p.Fields = append(p.Fields, rightFields...)
	}

	return nil
}

func (r *JoinRset) buildPlan(ctx context.Context, node interface{}) (plan.Plan, []*field.ResultField, error) {
	switch t := node.(type) {
	case *JoinRset:
		return &plans.JoinPlan{}, nil, nil
	case *TableSource:
		return r.buildSourcePlan(ctx, t)
	case nil:
		return nil, nil, nil
	default:
		return nil, nil, errors.Errorf("invalid join node %T", t)
	}
}

func (r *JoinRset) checkTableDuplicate(t *TableSource, tr *TableRset) error {
	if len(t.Name) > 0 {
		// use alias name
		_, ok := r.tableNames[t.Name]
		if ok {
			return errors.Errorf("%s: duplicate name %s", r, t.Name)
		}
		r.tableNames[t.Name] = true
		return nil
	}

	// first check ident name
	identName := t.String()
	_, ok := r.tableNames[identName]
	if ok {
		return errors.Errorf("%s: duplicate name %s", r, identName)
	}
	r.tableNames[identName] = true

	qualifiedName := tr.Schema + "." + tr.Name
	// we should check qualifed name too, e,g select * form t1 join test.t1
	if identName != qualifiedName {
		_, ok = r.tableNames[qualifiedName]
		if ok {
			return errors.Errorf("%s: duplicate name %s", r, identName)
		}
		r.tableNames[qualifiedName] = true
	}

	return nil
}

func (r *JoinRset) buildSourcePlan(ctx context.Context, t *TableSource) (plan.Plan, []*field.ResultField, error) {
	var (
		src interface{}
		tr  *TableRset
		err error
	)
	switch s := t.Source.(type) {
	case table.Ident:
		fullIdent := s.Full(ctx)
		tr, err = newTableRset(fullIdent.Schema.O, fullIdent.Name.O)
		if err != nil {
			return nil, nil, errors.Trace(err)
		}
		src = tr
		if err := r.checkTableDuplicate(t, tr); err != nil {
			return nil, nil, errors.Trace(err)
		}
	case stmt.Statement:
		src = s
	default:
		return nil, nil, errors.Errorf("invalid table source %T", t.Source)
	}

	var p plan.Plan
	switch x := src.(type) {
	case plan.Planner:
		if p, err = x.Plan(ctx); err != nil {
			return nil, nil, errors.Trace(err)
		}
	case plan.Plan:
		p = x
	default:
		return nil, nil, errors.Errorf("invalid table source %T, no Plan interface", t.Source)
	}

	var fields []*field.ResultField
	dupNames := make(map[string]struct{}, len(p.GetFields()))
	for _, nf := range p.GetFields() {
		f := nf.Clone()
		if t.Name != "" {
			f.TableName = t.Name
		}

		// duplicate column name in one table is not allowed.
		name := strings.ToLower(f.Name)
		if _, ok := dupNames[name]; ok {
			return nil, nil, errors.Errorf("Duplicate column name '%s'", name)
		}
		dupNames[name] = struct{}{}

		fields = append(fields, f)
	}

	return p, fields, nil
}

// Plan gets JoinPlan.
func (r *JoinRset) Plan(ctx context.Context) (plan.Plan, error) {
	r.tableNames = make(map[string]bool)
	p := &plans.JoinPlan{}
	if err := r.buildJoinPlan(ctx, p, r); err != nil {
		return nil, errors.Trace(err)
	}

	return p, nil
}

// MultipleTable checks if the JoinRset contains multiple tables.
func (r *JoinRset) MultipleTable() bool {
	if _, ok := r.Left.(*TableSource); ok {
		if r.Right == nil {
			return false
		}
	}
	return true
}
<|endoftext|>


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

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

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

package cephinstaller

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/parnurzeal/gorequest"
	"github.com/skyrings/skyring-common/conf"
	"github.com/skyrings/skyring-common/models"
	"github.com/skyrings/skyring-common/provisioner"
	"github.com/skyrings/skyring-common/tools/logger"
	"github.com/skyrings/skyring-common/tools/task"
	"github.com/skyrings/skyring-common/utils"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"
)

type CephInstaller struct {
}

const (
	ProviderName                      = "ceph-installer"
	CEPH_INSTALLER_API_DEFAULT_PREFIX = "api"
	CEPH_INSTALLER_API_PORT           = 8181
	MON                               = "MON"
	OSD                               = "OSD"
)

type InstallReq struct {
	Hosts         []string `json:"hosts"`
	RedhatStorage bool     `json:"redhat_storage"`
	RedhatUseCdn  bool     `json:"redhat_use_cdn"`
}

type Task struct {
	Endpoint   string `json:"endpoint"`
	Succeeded  bool   `json:"succeeded"`
	Stdout     string `json:"stdout"`
	Started    string `json:"started"`
	ExitCode   int    `json:"exit_code"`
	Ended      string `json:"ended"`
	Command    string `json:"command"`
	Stderr     string `json:"stderr"`
	Identifier string `json:"identifier"`
}

var httprequest = gorequest.New()

func init() {
	provisioner.RegisterProvider(ProviderName, func(config io.Reader) (provisioner.Provisioner, error) {
		return New(config)
	})
}

func New(config io.Reader) (*CephInstaller, error) {
	installer := new(CephInstaller)
	installer.LoadRoutes()
	return installer, nil
}

func (c CephInstaller) Install(ctxt string, t *task.Task, providerName string, nodes []models.ClusterNode) []models.ClusterNode {

	db_nodes, err := util.GetNodesByIdStr(nodes)
	if err != nil {
		logger.Get().Error("%s-Error getting nodes while package installation: %v", ctxt, err)
		return nodes
	}

	var (
		wg          sync.WaitGroup
		failedNodes []models.ClusterNode
		syncMutex   sync.Mutex
	)

	for _, node := range nodes {
		wg.Add(1)
		go func(node models.ClusterNode, hostname string) {
			defer wg.Done()
			var route models.ApiRoute
			hosts := []string{hostname}
			if util.StringInSlice(MON, node.NodeType) {
				route = CEPH_INSTALLER_API_ROUTES["monInstall"]
			} else if util.StringInSlice(OSD, node.NodeType) {
				route = CEPH_INSTALLER_API_ROUTES["osdInstall"]
			}
			/*
				TODO replace the map with commented code once the ceph-installer support
				available
			*/
			/*data := InstallReq{Hosts: hosts,
				RedhatStorage: conf.SystemConfig.Provisioners[providerName].RedhatStorage,
				RedhatUseCdn:  conf.SystemConfig.Provisioners[providerName].RedhatUseCdn}
			resp, body, errs := httprequest.Post(formUrl(route)).SendStruct(data).End()*/
			data := make(map[string]interface{})
			data["hosts"] = hosts
			data["redhat_storage"] = conf.SystemConfig.Provisioners[providerName].RedhatStorage
			jsonString, err := json.Marshal(data)
			if err != nil {
				logger.Get().Error("%s-Error marshalling data: %v", ctxt, err)
				return
			}
			resp, body, errs := httprequest.Post(formUrl(route)).Send(string(jsonString)).End()
			respData, err := parseInstallResponseData(ctxt, resp, body, errs)
			if err != nil {
				syncMutex.Lock()
				defer syncMutex.Unlock()
				failedNodes = append(failedNodes, node)
				return
			}
			if ok := syncRequestStatus(ctxt, respData.Identifier); !ok {
				syncMutex.Lock()
				defer syncMutex.Unlock()
				failedNodes = append(failedNodes, node)
				return
			}
			t.UpdateStatus("Installed packages on: %s", hostname)
		}(node, db_nodes[node.NodeId].Hostname)
	}
	wg.Wait()

	return failedNodes
}
func (c CephInstaller) Configure(ctxt string, t *task.Task, reqType string, data map[string]interface{}) error {
	var (
		resp  *http.Response
		body  string
		errs  []error
		route models.ApiRoute
	)
	if reqType == MON {
		route = CEPH_INSTALLER_API_ROUTES["monConfigure"]
		jsonString, err := json.Marshal(data)
		if err != nil {
			return err
		}
		resp, body, errs = httprequest.Post(formUrl(route)).Send(jsonString).End()

	} else if reqType == OSD {
		route = CEPH_INSTALLER_API_ROUTES["osdConfigure	"]
		jsonString, err := json.Marshal(data)
		if err != nil {
			return err
		}
		resp, body, errs = httprequest.Post(formUrl(route)).Send(jsonString).End()

	}
	respData, err := parseInstallResponseData(ctxt, resp, body, errs)
	if err != nil {
		return err
	}
	if ok := syncRequestStatus(ctxt, respData.Identifier); !ok {
		return err
	}
	return nil
}

func formUrl(route models.ApiRoute) string {
	url := fmt.Sprintf("http://localhost:%d/%s/%s", CEPH_INSTALLER_API_PORT, CEPH_INSTALLER_API_DEFAULT_PREFIX, route.Pattern)
	return url
}

func syncRequestStatus(ctxt string, taskId string) bool {
	var status bool

	for {
		time.Sleep(10 * time.Second)
		taskData, err := getTaskData(ctxt, taskId)
		if err != nil {
			return status
		}

		if taskData.Ended != "" {
			// If request has failed return with error
			if taskData.Succeeded {
				status = true
			} else {
				logger.Get().Error("%s-Error while installing Packages. stdout: %v. stderr:%v", ctxt, taskData.Stdout, taskData.Stderr)
			}
			break
		}
	}

	return status
}

func getTaskData(ctxt string, taskId string) (Task, error) {

	var respData Task
	route := CEPH_INSTALLER_API_ROUTES["taskStatus"]
	route.Pattern = strings.Replace(route.Pattern, "{id}", taskId, 1)
	resp, body, errs := httprequest.Get(formUrl(route)).End()
	if len(errs) > 0 {
		logger.Get().Error("%s-Error getting task status for task:%v.Err:%v", ctxt, taskId, errs)
		return respData, errors.New("Error getting task status")
	}
	if resp.StatusCode != http.StatusOK {
		logger.Get().Error("%s-Error Getting Task Status:%v", ctxt, taskId)
		return respData, errors.New("Error getting task status")
	}

	if err := json.Unmarshal([]byte(body), &respData); err != nil {
		logger.Get().Error("%s-Unable to unmarshal response. error: %v", ctxt, err)
		return respData, errors.New("Unable to unmarshal response")
	}
	return respData, nil
}

func parseInstallResponseData(ctxt string, resp *http.Response, body string, errs []error) (Task, error) {
	var respData Task
	if len(errs) > 0 {
		logger.Get().Error("%s-Error Installing Packages:%v", ctxt, errs)
		return respData, errors.New("Error Installing Packages")
	}
	if resp.StatusCode != http.StatusOK {
		logger.Get().Error("%s-Error Installing Packages", ctxt)
		return respData, errors.New("Error Installing Packages. Ceph-installer failed")
	}
	if err := json.Unmarshal([]byte(body), &respData); err != nil {
		logger.Get().Error("%s-Unable to unmarshal response. error: %v", ctxt, err)
		return respData, errors.New("Unable to unmarshal response")
	}
	return respData, nil
}
<commit_msg>skyring-common: create cluster integration<commit_after>/*Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package cephinstaller

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/parnurzeal/gorequest"
	"github.com/skyrings/skyring-common/conf"
	"github.com/skyrings/skyring-common/models"
	"github.com/skyrings/skyring-common/provisioner"
	"github.com/skyrings/skyring-common/tools/logger"
	"github.com/skyrings/skyring-common/tools/task"
	"github.com/skyrings/skyring-common/utils"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"
)

type CephInstaller struct {
}

const (
	ProviderName                      = "ceph-installer"
	CEPH_INSTALLER_API_DEFAULT_PREFIX = "api"
	CEPH_INSTALLER_API_PORT           = 8181
	MON                               = "MON"
	OSD                               = "OSD"
)

type InstallReq struct {
	Hosts         []string `json:"hosts"`
	RedhatStorage bool     `json:"redhat_storage"`
	RedhatUseCdn  bool     `json:"redhat_use_cdn"`
}

type Task struct {
	Endpoint   string `json:"endpoint"`
	Succeeded  bool   `json:"succeeded"`
	Stdout     string `json:"stdout"`
	Started    string `json:"started"`
	ExitCode   int    `json:"exit_code"`
	Ended      string `json:"ended"`
	Command    string `json:"command"`
	Stderr     string `json:"stderr"`
	Identifier string `json:"identifier"`
}

var httprequest = gorequest.New()

func init() {
	provisioner.RegisterProvider(ProviderName, func(config io.Reader) (provisioner.Provisioner, error) {
		return New(config)
	})
}

func New(config io.Reader) (*CephInstaller, error) {
	installer := new(CephInstaller)
	installer.LoadRoutes()
	return installer, nil
}

func (c CephInstaller) Install(ctxt string, t *task.Task, providerName string, nodes []models.ClusterNode) []models.ClusterNode {

	db_nodes, err := util.GetNodesByIdStr(nodes)
	if err != nil {
		logger.Get().Error("%s-Error getting nodes while package installation: %v", ctxt, err)
		return nodes
	}

	var (
		wg          sync.WaitGroup
		failedNodes []models.ClusterNode
		syncMutex   sync.Mutex
	)

	for _, node := range nodes {
		wg.Add(1)
		go func(node models.ClusterNode, hostname string) {
			defer wg.Done()
			var route models.ApiRoute
			hosts := []string{hostname}
			data := make(map[string]interface{})
			if util.StringInSlice(MON, node.NodeType) {
				route = CEPH_INSTALLER_API_ROUTES["monInstall"]
				data["calamari"] = true
			} else if util.StringInSlice(OSD, node.NodeType) {
				route = CEPH_INSTALLER_API_ROUTES["osdInstall"]
			}

			data["hosts"] = hosts
			data["redhat_storage"] = conf.SystemConfig.Provisioners[providerName].RedhatStorage

			reqData, err := formConfigureData(data)
			if err != nil {
				failedNodes = append(failedNodes, node)
				return
			}

			resp, body, errs := httprequest.Post(formUrl(route)).Send(reqData).End()

			respData, err := parseInstallResponseData(ctxt, resp, body, errs)
			if err != nil {
				syncMutex.Lock()
				defer syncMutex.Unlock()
				failedNodes = append(failedNodes, node)
				return
			}
			if ok := syncRequestStatus(ctxt, respData.Identifier); !ok {
				syncMutex.Lock()
				defer syncMutex.Unlock()
				failedNodes = append(failedNodes, node)
				return
			}
			t.UpdateStatus("Installed packages on: %s", hostname)
		}(node, db_nodes[node.NodeId].Hostname)
	}
	wg.Wait()

	return failedNodes
}
func (c CephInstaller) Configure(ctxt string, t *task.Task, reqType string, data map[string]interface{}) error {
	var (
		resp  *http.Response
		body  string
		errs  []error
		route models.ApiRoute
	)
	reqData, err := formConfigureData(data)
	if err != nil {
		return err
	}
	if reqType == MON {
		route = CEPH_INSTALLER_API_ROUTES["monConfigure"]

	} else if reqType == OSD {
		route = CEPH_INSTALLER_API_ROUTES["osdConfigure"]

	}

	resp, body, errs = httprequest.Post(formUrl(route)).Send(reqData).End()

	respData, err := parseInstallResponseData(ctxt, resp, body, errs)
	if err != nil {
		return err
	}
	if ok := syncRequestStatus(ctxt, respData.Identifier); !ok {
		return errors.New("MON Configuration Failed")
	}
	return nil
}

func formUrl(route models.ApiRoute) string {
	url := fmt.Sprintf("http://localhost:%d/%s/%s", CEPH_INSTALLER_API_PORT, CEPH_INSTALLER_API_DEFAULT_PREFIX, route.Pattern)
	return url
}

func syncRequestStatus(ctxt string, taskId string) bool {
	var status bool

	for {
		time.Sleep(10 * time.Second)
		taskData, err := getTaskData(ctxt, taskId)
		if err != nil {
			return status
		}

		if taskData.Ended != "" {
			// If request has failed return with error
			if taskData.Succeeded {
				status = true
			} else {
				logger.Get().Error("%s-Error while installing Packages. stdout: %v. stderr:%v", ctxt, taskData.Stdout, taskData.Stderr)
			}
			break
		}
	}

	return status
}

func getTaskData(ctxt string, taskId string) (Task, error) {

	var respData Task
	route := CEPH_INSTALLER_API_ROUTES["taskStatus"]
	route.Pattern = strings.Replace(route.Pattern, "{id}", taskId, 1)
	resp, body, errs := httprequest.Get(formUrl(route)).End()
	if len(errs) > 0 {
		logger.Get().Error("%s-Error getting task status for task:%v.Err:%v", ctxt, taskId, errs)
		return respData, errors.New("Error getting task status")
	}
	if resp.StatusCode != http.StatusOK {
		logger.Get().Error("%s-Error Getting Task Status:%v", ctxt, taskId)
		return respData, errors.New("Error getting task status")
	}

	if err := json.Unmarshal([]byte(body), &respData); err != nil {
		logger.Get().Error("%s-Unable to unmarshal response. error: %v", ctxt, err)
		return respData, errors.New("Unable to unmarshal response")
	}
	return respData, nil
}

func parseInstallResponseData(ctxt string, resp *http.Response, body string, errs []error) (Task, error) {
	var respData Task
	if len(errs) > 0 {
		logger.Get().Error("%s-Error Installing Packages:%v", ctxt, errs)
		return respData, errors.New("Error Sending ceph-installer request")
	}
	if resp.StatusCode != http.StatusOK {
		logger.Get().Error("%s-Error Sending ceph-installer request", ctxt)
		return respData, errors.New("Error Sending ceph-installer request. Ceph-installer failed")
	}
	if err := json.Unmarshal([]byte(body), &respData); err != nil {
		logger.Get().Error("%s-Unable to unmarshal response. error: %v", ctxt, err)
		return respData, errors.New("Unable to unmarshal response")
	}
	return respData, nil
}

func formConfigureData(data map[string]interface{}) (string, error) {

	request, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(request), nil

}
<|endoftext|>


<commit_before>// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// author  			sigu-399
// author-github 	https://github.com/sigu-399
// author-mail		sigu.399@gmail.com
//
// repository-name	gojsonreference
// repository-desc	An implementation of JSON Reference - Go language
//
// description		Main and unique file.
//
// created      	26-02-2013

package gojsonreference

import (
	"errors"
	"net/url"
	"strings"

	"github.com/binary132/gojsonpointer"
)

const (
	const_fragment_char = `#`
)

func NewJsonReference(jsonReferenceString string) (JsonReference, error) {
	var r JsonReference

	var err error

	r.referenceUrl, err = url.Parse(jsonReferenceString)
	if err != nil {
		return JsonReference{}, err
	}

	r.referencePointer, err = gojsonpointer.NewJsonPointer(r.referenceUrl.Fragment)
	if err != nil {
		return JsonReference{}, err
	}

	return r, err
}

type JsonReference struct {
	referenceUrl     *url.URL
	referencePointer gojsonpointer.JsonPointer
}

func (r *JsonReference) GetUrl() *url.URL {
	return r.referenceUrl
}

func (r *JsonReference) GetPointer() *gojsonpointer.JsonPointer {
	return &r.referencePointer
}

func (r *JsonReference) String() string {

	if r.referenceUrl != nil {
		return r.referenceUrl.String()
	}

	return r.referencePointer.String()
}

// Creates a new reference from a parent and a child
// If the child cannot inherit from the parent, an error is returned
func (r *JsonReference) Inherits(child JsonReference) (*JsonReference, error) {

	if r.referenceUrl == nil {
		return nil, errors.New("parent reference nil")
	}

	if !r.referenceUrl.IsAbs() {
		return nil, errors.New("parent reference must be absolute URL.")
	}

	if r.referenceUrl.Scheme != "http" && r.referenceUrl.Scheme != "file" {
		return nil, errors.New("scheme type " + r.referenceUrl.Scheme + " not handled")
	}

	if child.referenceUrl.IsAbs() {
		if child.referenceUrl.Scheme != r.referenceUrl.Scheme {
			return nil, errors.New("scheme of child " + child.String() +
				" incompatible with scheme of parent " + r.String())
		}

		if r.referenceUrl.Host != child.referenceUrl.Host {
			return nil, errors.New("references have different hosts")
		}
	}

	inheritedReference, err := NewJsonReference(r.String())
	if err != nil {
		return nil, err
	}

	// Child reference is not a fragment, and has a different path than parent
	//if child.referenceUrl != nil && child.referenceUrl.Path != "" {
	if child.referenceUrl.Path != "" {
		if !strings.HasPrefix(child.referenceUrl.Path, r.referenceUrl.Path) {
			return nil, errors.New("child reference " + child.String() +
				" has divergent path " + child.referenceUrl.Path +
				" from parent " + r.String() +
				", which has path " + r.referenceUrl.Path)
		}

		inheritedReference.referenceUrl.Path = child.referenceUrl.Path
	}

	if child.referenceUrl != nil && child.referenceUrl.Fragment != "" {
		if !strings.HasPrefix(child.referenceUrl.Fragment, r.referenceUrl.Fragment) {
			return nil, errors.New("child reference " + child.String() +
				" has divergent pointer " + child.referenceUrl.Fragment +
				" from parent " + r.String() +
				", which has pointer " + r.referenceUrl.Fragment)
		}

		inheritedReference.referenceUrl.Fragment = child.referenceUrl.Fragment
		inheritedReference.referencePointer = child.referencePointer
	}

	return &inheritedReference, nil
}
<commit_msg>Using pinned .v1 gojsonpointer<commit_after>// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// author  			sigu-399
// author-github 	https://github.com/sigu-399
// author-mail		sigu.399@gmail.com
//
// repository-name	gojsonreference
// repository-desc	An implementation of JSON Reference - Go language
//
// description		Main and unique file.
//
// created      	26-02-2013

package gojsonreference

import (
	"errors"
	"net/url"
	"strings"

	"gopkg.in/binary132/gojsonpointer.v1"
)

const (
	const_fragment_char = `#`
)

func NewJsonReference(jsonReferenceString string) (JsonReference, error) {
	var r JsonReference

	var err error

	r.referenceUrl, err = url.Parse(jsonReferenceString)
	if err != nil {
		return JsonReference{}, err
	}

	r.referencePointer, err = gojsonpointer.NewJsonPointer(r.referenceUrl.Fragment)
	if err != nil {
		return JsonReference{}, err
	}

	return r, err
}

type JsonReference struct {
	referenceUrl     *url.URL
	referencePointer gojsonpointer.JsonPointer
}

func (r *JsonReference) GetUrl() *url.URL {
	return r.referenceUrl
}

func (r *JsonReference) GetPointer() *gojsonpointer.JsonPointer {
	return &r.referencePointer
}

func (r *JsonReference) String() string {

	if r.referenceUrl != nil {
		return r.referenceUrl.String()
	}

	return r.referencePointer.String()
}

// Creates a new reference from a parent and a child
// If the child cannot inherit from the parent, an error is returned
func (r *JsonReference) Inherits(child JsonReference) (*JsonReference, error) {

	if r.referenceUrl == nil {
		return nil, errors.New("parent reference nil")
	}

	if !r.referenceUrl.IsAbs() {
		return nil, errors.New("parent reference must be absolute URL.")
	}

	if r.referenceUrl.Scheme != "http" && r.referenceUrl.Scheme != "file" {
		return nil, errors.New("scheme type " + r.referenceUrl.Scheme + " not handled")
	}

	if child.referenceUrl.IsAbs() {
		if child.referenceUrl.Scheme != r.referenceUrl.Scheme {
			return nil, errors.New("scheme of child " + child.String() +
				" incompatible with scheme of parent " + r.String())
		}

		if r.referenceUrl.Host != child.referenceUrl.Host {
			return nil, errors.New("references have different hosts")
		}
	}

	inheritedReference, err := NewJsonReference(r.String())
	if err != nil {
		return nil, err
	}

	// Child reference is not a fragment, and has a different path than parent
	//if child.referenceUrl != nil && child.referenceUrl.Path != "" {
	if child.referenceUrl.Path != "" {
		if !strings.HasPrefix(child.referenceUrl.Path, r.referenceUrl.Path) {
			return nil, errors.New("child reference " + child.String() +
				" has divergent path " + child.referenceUrl.Path +
				" from parent " + r.String() +
				", which has path " + r.referenceUrl.Path)
		}

		inheritedReference.referenceUrl.Path = child.referenceUrl.Path
	}

	if child.referenceUrl != nil && child.referenceUrl.Fragment != "" {
		if !strings.HasPrefix(child.referenceUrl.Fragment, r.referenceUrl.Fragment) {
			return nil, errors.New("child reference " + child.String() +
				" has divergent pointer " + child.referenceUrl.Fragment +
				" from parent " + r.String() +
				", which has pointer " + r.referenceUrl.Fragment)
		}

		inheritedReference.referenceUrl.Fragment = child.referenceUrl.Fragment
		inheritedReference.referencePointer = child.referencePointer
	}

	return &inheritedReference, nil
}
<|endoftext|>


<commit_before>package aws

import (
	"bytes"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/mitchellh/goamz/ec2"
)

func resourceAwsSecurityGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSecurityGroupCreate,
		Read:   resourceAwsSecurityGroupRead,
		Update: resourceAwsSecurityGroupUpdate,
		Delete: resourceAwsSecurityGroupDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"description": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"ingress": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"cidr_blocks": &schema.Schema{
							Type:     schema.TypeList,
							Optional: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
						},

						"security_groups": &schema.Schema{
							Type:     schema.TypeList,
							Optional: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
						},

						"self": &schema.Schema{
							Type:     schema.TypeBool,
							Optional: true,
						},
					},
				},
				Set: resourceAwsSecurityGroupIngressHash,
			},

			"owner_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsSecurityGroupIngressHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))

	// We need to make sure to sort the strings below so that we always
	// generate the same hash code no matter what is in the set.
	if v, ok := m["cidr_blocks"]; ok {
		vs := v.([]interface{})
		s := make([]string, len(vs))
		for i, raw := range vs {
			s[i] = raw.(string)
		}
		sort.Strings(s)

		for _, v := range s {
			buf.WriteString(fmt.Sprintf("%s-", v))
		}
	}
	if v, ok := m["security_groups"]; ok {
		vs := v.([]interface{})
		s := make([]string, len(vs))
		for i, raw := range vs {
			s[i] = raw.(string)
		}
		sort.Strings(s)

		for _, v := range s {
			buf.WriteString(fmt.Sprintf("%s-", v))
		}
	}

	return hashcode.String(buf.String())
}

func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	securityGroupOpts := ec2.SecurityGroup{
		Name: d.Get("name").(string),
	}

	if v := d.Get("vpc_id"); v != nil {
		securityGroupOpts.VpcId = v.(string)
	}

	if v := d.Get("description"); v != nil {
		securityGroupOpts.Description = v.(string)
	}

	log.Printf(
		"[DEBUG] Security Group create configuration: %#v", securityGroupOpts)
	createResp, err := ec2conn.CreateSecurityGroup(securityGroupOpts)
	if err != nil {
		return fmt.Errorf("Error creating Security Group: %s", err)
	}

	d.SetId(createResp.Id)

	log.Printf("[INFO] Security Group ID: %s", d.Id())

	// Wait for the security group to truly exist
	log.Printf(
		"[DEBUG] Waiting for Security Group (%s) to exist",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{""},
		Target:  "exists",
		Refresh: SGStateRefreshFunc(ec2conn, d.Id()),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for Security Group (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsSecurityGroupUpdate(d, meta)
}

func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
	if err != nil {
		return err
	}
	if sgRaw == nil {
		d.SetId("")
		return nil
	}
	group := sgRaw.(*ec2.SecurityGroupInfo).SecurityGroup

	if d.HasChange("ingress") {
		o, n := d.GetChange("ingress")
		if o == nil {
			o = new(schema.Set)
		}
		if n == nil {
			n = new(schema.Set)
		}

		os := o.(*schema.Set)
		ns := n.(*schema.Set)

		remove := expandIPPerms(d.Id(), os.Difference(ns).List())
		add := expandIPPerms(d.Id(), ns.Difference(os).List())

		// TODO: We need to handle partial state better in the in-between
		// in this update.

		// TODO: It'd be nicer to authorize before removing, but then we have
		// to deal with complicated unrolling to get individual CIDR blocks
		// to avoid authorizing already authorized sources. Removing before
		// adding is easier here, and Terraform should be fast enough to
		// not have service issues.

		if len(remove) > 0 {
			// Revoke the old rules
			_, err = ec2conn.RevokeSecurityGroup(group, remove)
			if err != nil {
				return fmt.Errorf("Error authorizing security group ingress rules: %s", err)
			}
		}

		if len(add) > 0 {
			// Authorize the new rules
			_, err := ec2conn.AuthorizeSecurityGroup(group, add)
			if err != nil {
				return fmt.Errorf("Error authorizing security group ingress rules: %s", err)
			}
		}
	}

	return nil
}

func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[DEBUG] Security Group destroy: %v", d.Id())

	_, err := ec2conn.DeleteSecurityGroup(ec2.SecurityGroup{Id: d.Id()})
	if err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok && ec2err.Code == "InvalidGroup.NotFound" {
			return nil
		}
	}

	return err
}

func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
	if err != nil {
		return err
	}
	if sgRaw == nil {
		d.SetId("")
		return nil
	}

	sg := sgRaw.(*ec2.SecurityGroupInfo)

	// Gather our ingress rules
	ingressRules := make([]map[string]interface{}, len(sg.IPPerms))
	for i, perm := range sg.IPPerms {
		n := make(map[string]interface{})
		n["from_port"] = perm.FromPort
		n["protocol"] = perm.Protocol
		n["to_port"] = perm.ToPort

		if len(perm.SourceIPs) > 0 {
			n["cidr_blocks"] = perm.SourceIPs
		}

		var groups []string
		if len(perm.SourceGroups) > 0 {
			groups = flattenSecurityGroups(perm.SourceGroups)
		}
		for i, id := range groups {
			if id == d.Id() {
				groups[i], groups = groups[len(groups)-1], groups[:len(groups)-1]
				n["self"] = true
			}
		}
		if len(groups) > 0 {
			n["security_groups"] = groups
		}

		ingressRules[i] = n
	}

	d.Set("description", sg.Description)
	d.Set("name", sg.Name)
	d.Set("vpc_id", sg.VpcId)
	d.Set("owner_id", sg.OwnerId)
	d.Set("ingress", ingressRules)

	return nil
}

// SGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a security group.
func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		sgs := []ec2.SecurityGroup{ec2.SecurityGroup{Id: id}}
		resp, err := conn.SecurityGroups(sgs, nil)
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok {
				if ec2err.Code == "InvalidSecurityGroupID.NotFound" ||
					ec2err.Code == "InvalidGroup.NotFound" {
					resp = nil
					err = nil
				}
			}

			if err != nil {
				log.Printf("Error on SGStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			return nil, "", nil
		}

		group := &resp.Groups[0]
		return group, "exists", nil
	}
}
<commit_msg>providers/aws: retry deleting security group for some time [GH-436]<commit_after>package aws

import (
	"bytes"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/mitchellh/goamz/ec2"
)

func resourceAwsSecurityGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSecurityGroupCreate,
		Read:   resourceAwsSecurityGroupRead,
		Update: resourceAwsSecurityGroupUpdate,
		Delete: resourceAwsSecurityGroupDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"description": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"ingress": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},

						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

						"cidr_blocks": &schema.Schema{
							Type:     schema.TypeList,
							Optional: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
						},

						"security_groups": &schema.Schema{
							Type:     schema.TypeList,
							Optional: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
						},

						"self": &schema.Schema{
							Type:     schema.TypeBool,
							Optional: true,
						},
					},
				},
				Set: resourceAwsSecurityGroupIngressHash,
			},

			"owner_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsSecurityGroupIngressHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))

	// We need to make sure to sort the strings below so that we always
	// generate the same hash code no matter what is in the set.
	if v, ok := m["cidr_blocks"]; ok {
		vs := v.([]interface{})
		s := make([]string, len(vs))
		for i, raw := range vs {
			s[i] = raw.(string)
		}
		sort.Strings(s)

		for _, v := range s {
			buf.WriteString(fmt.Sprintf("%s-", v))
		}
	}
	if v, ok := m["security_groups"]; ok {
		vs := v.([]interface{})
		s := make([]string, len(vs))
		for i, raw := range vs {
			s[i] = raw.(string)
		}
		sort.Strings(s)

		for _, v := range s {
			buf.WriteString(fmt.Sprintf("%s-", v))
		}
	}

	return hashcode.String(buf.String())
}

func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	securityGroupOpts := ec2.SecurityGroup{
		Name: d.Get("name").(string),
	}

	if v := d.Get("vpc_id"); v != nil {
		securityGroupOpts.VpcId = v.(string)
	}

	if v := d.Get("description"); v != nil {
		securityGroupOpts.Description = v.(string)
	}

	log.Printf(
		"[DEBUG] Security Group create configuration: %#v", securityGroupOpts)
	createResp, err := ec2conn.CreateSecurityGroup(securityGroupOpts)
	if err != nil {
		return fmt.Errorf("Error creating Security Group: %s", err)
	}

	d.SetId(createResp.Id)

	log.Printf("[INFO] Security Group ID: %s", d.Id())

	// Wait for the security group to truly exist
	log.Printf(
		"[DEBUG] Waiting for Security Group (%s) to exist",
		d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{""},
		Target:  "exists",
		Refresh: SGStateRefreshFunc(ec2conn, d.Id()),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for Security Group (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsSecurityGroupUpdate(d, meta)
}

func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
	if err != nil {
		return err
	}
	if sgRaw == nil {
		d.SetId("")
		return nil
	}
	group := sgRaw.(*ec2.SecurityGroupInfo).SecurityGroup

	if d.HasChange("ingress") {
		o, n := d.GetChange("ingress")
		if o == nil {
			o = new(schema.Set)
		}
		if n == nil {
			n = new(schema.Set)
		}

		os := o.(*schema.Set)
		ns := n.(*schema.Set)

		remove := expandIPPerms(d.Id(), os.Difference(ns).List())
		add := expandIPPerms(d.Id(), ns.Difference(os).List())

		// TODO: We need to handle partial state better in the in-between
		// in this update.

		// TODO: It'd be nicer to authorize before removing, but then we have
		// to deal with complicated unrolling to get individual CIDR blocks
		// to avoid authorizing already authorized sources. Removing before
		// adding is easier here, and Terraform should be fast enough to
		// not have service issues.

		if len(remove) > 0 {
			// Revoke the old rules
			_, err = ec2conn.RevokeSecurityGroup(group, remove)
			if err != nil {
				return fmt.Errorf("Error authorizing security group ingress rules: %s", err)
			}
		}

		if len(add) > 0 {
			// Authorize the new rules
			_, err := ec2conn.AuthorizeSecurityGroup(group, add)
			if err != nil {
				return fmt.Errorf("Error authorizing security group ingress rules: %s", err)
			}
		}
	}

	return nil
}

func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[DEBUG] Security Group destroy: %v", d.Id())

	return resource.Retry(5 * time.Minute, func() error {
		_, err := ec2conn.DeleteSecurityGroup(ec2.SecurityGroup{Id: d.Id()})
		if err != nil {
			ec2err, ok := err.(*ec2.Error)
			if ok && ec2err.Code == "InvalidGroup.NotFound" {
				return nil
			}
		}

		return err
	})
}

func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())()
	if err != nil {
		return err
	}
	if sgRaw == nil {
		d.SetId("")
		return nil
	}

	sg := sgRaw.(*ec2.SecurityGroupInfo)

	// Gather our ingress rules
	ingressRules := make([]map[string]interface{}, len(sg.IPPerms))
	for i, perm := range sg.IPPerms {
		n := make(map[string]interface{})
		n["from_port"] = perm.FromPort
		n["protocol"] = perm.Protocol
		n["to_port"] = perm.ToPort

		if len(perm.SourceIPs) > 0 {
			n["cidr_blocks"] = perm.SourceIPs
		}

		var groups []string
		if len(perm.SourceGroups) > 0 {
			groups = flattenSecurityGroups(perm.SourceGroups)
		}
		for i, id := range groups {
			if id == d.Id() {
				groups[i], groups = groups[len(groups)-1], groups[:len(groups)-1]
				n["self"] = true
			}
		}
		if len(groups) > 0 {
			n["security_groups"] = groups
		}

		ingressRules[i] = n
	}

	d.Set("description", sg.Description)
	d.Set("name", sg.Name)
	d.Set("vpc_id", sg.VpcId)
	d.Set("owner_id", sg.OwnerId)
	d.Set("ingress", ingressRules)

	return nil
}

// SGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a security group.
func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		sgs := []ec2.SecurityGroup{ec2.SecurityGroup{Id: id}}
		resp, err := conn.SecurityGroups(sgs, nil)
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok {
				if ec2err.Code == "InvalidSecurityGroupID.NotFound" ||
					ec2err.Code == "InvalidGroup.NotFound" {
					resp = nil
					err = nil
				}
			}

			if err != nil {
				log.Printf("Error on SGStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			return nil, "", nil
		}

		group := &resp.Groups[0]
		return group, "exists", nil
	}
}
<|endoftext|>