From 145ec4ea73c52ecae5c52d40187f9461745eccc2 Mon Sep 17 00:00:00 2001 From: Fabio Barone Date: Fri, 12 May 2017 17:28:14 -0500 Subject: [PATCH] p2p/simulations: scenarios support; HTTP OPTIONS support --- p2p/simulations/http.go | 58 +++++++++++++++++++-- p2p/simulations/mocker.go | 2 + swarm/network/simulations/overlay.go | 77 ++++++++++++++++++++++++++-- 3 files changed, 130 insertions(+), 7 deletions(-) diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index cda7493dc514..ba12f993de4e 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -244,6 +244,10 @@ type ServerConfig struct { // POST request to /networks//mock and is expected to // generate some mock events in the network Mocker func(*Network) + // In case of multiple mockers, set the default here + DefaultMockerId string + // map of Mockers + Mockers map[string]*MockerConfig } // Server is an HTTP server providing an API to create and manage simulation @@ -268,13 +272,15 @@ func NewServer(config *ServerConfig) *Server { networks: make(map[string]*Network), } + s.OPTIONS("/networks", s.Options) s.POST("/networks", s.CreateNetwork) s.GET("/networks", s.GetNetworks) s.GET("/networks/:netid", s.GetNetwork) s.GET("/networks/:netid/events", s.StreamNetworkEvents) s.POST("/networks/:netid/snapshots/create", s.CreateSnapshot) s.POST("/networks/:netid/snapshots/load", s.LoadSnapshot) - s.POST("/networks/:netid/mock", s.StartMocker) + s.POST("/networks/:netid/mock/:mockid", s.StartMocker) + s.GET("/networks/:netid/mock", s.GetMocker) s.POST("/networks/:netid/nodes", s.CreateNode) s.GET("/networks/:netid/nodes", s.GetNodes) s.GET("/networks/:netid/nodes/:nodeid", s.GetNode) @@ -335,17 +341,42 @@ func (s *Server) GetNetwork(w http.ResponseWriter, req *http.Request) { s.JSON(w, http.StatusOK, network) } +//Get the info for a particular mocker +func (s *Server) GetMocker(w http.ResponseWriter, req *http.Request) { + m := make(map[string]string) + + for k, v := range s.Mockers { + m[k] = v.Description + } + + s.JSON(w, http.StatusOK, m) +} + func (s *Server) StartMocker(w http.ResponseWriter, req *http.Request) { network := req.Context().Value("network").(*Network) + mockerid := req.Context().Value("mock").(string) - if s.Mocker == nil { + if len(s.Mockers) == 0 { http.Error(w, "mocker not configured", http.StatusInternalServerError) return } - go s.Mocker(network) + if mockerid == "default" { + //choose the default mocker + mockerid = s.DefaultMockerId + } - w.WriteHeader(http.StatusOK) + if mocker, ok := s.Mockers[mockerid]; ok { + if mocker.Mocker == nil { + http.Error(w, "mocker not configured", http.StatusInternalServerError) + return + } + go mocker.Mocker(network) + w.WriteHeader(http.StatusOK) + } else { + http.Error(w, "invalid mockerid provided", http.StatusBadRequest) + return + } } // StreamNetworkEvents streams network events as a server-sent-events stream @@ -521,6 +552,12 @@ func (s *Server) DisconnectNode(w http.ResponseWriter, req *http.Request) { s.JSON(w, http.StatusOK, node.NodeInfo()) } +//Options +func (s *Server) Options(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + return +} + // NodeRPC proxies node RPC requests via a WebSocket connection func (s *Server) NodeRPC(w http.ResponseWriter, req *http.Request) { node := req.Context().Value("node").(*Node) @@ -553,6 +590,11 @@ func (s *Server) DELETE(path string, handle http.HandlerFunc) { s.router.DELETE(path, s.wrapHandler(handle)) } +// OPTIONS registers a handler for OPTIONS requests to a particular path +func (s *Server) OPTIONS(path string, handle http.HandlerFunc) { + s.router.OPTIONS("/*path", s.wrapHandler(handle)) +} + // JSON sends "data" as a JSON HTTP response func (s *Server) JSON(w http.ResponseWriter, status int, data interface{}) { w.Header().Set("Content-Type", "application/json") @@ -618,6 +660,14 @@ func (s *Server) wrapHandler(handler http.HandlerFunc) httprouter.Handle { ctx = context.WithValue(ctx, "peer", peer) } + if id := params.ByName("mockid"); id != "" { + if network == nil { + http.NotFound(w, req) + return + } + ctx = context.WithValue(ctx, "mock", id) + } + handler(w, req.WithContext(ctx)) } } diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go index 8f03c801d62a..f4cf2732ae0b 100644 --- a/p2p/simulations/mocker.go +++ b/p2p/simulations/mocker.go @@ -15,6 +15,8 @@ type MockerConfig struct { Id string NodeCount int UpdateInterval int + Mocker func(*Network) + Description string SwitchonRate int // fraction of off nodes switching on DropoutRate int // fraction of on nodes dropping out NewConnCount int // new connection per node per tick diff --git a/swarm/network/simulations/overlay.go b/swarm/network/simulations/overlay.go index 5dcfea357437..198de6639448 100644 --- a/swarm/network/simulations/overlay.go +++ b/swarm/network/simulations/overlay.go @@ -90,7 +90,32 @@ func NewSimNode(id *adapters.NodeId, snapshot []byte) node.Service { } } -func mocker(net *simulations.Network) { +func createMockers() map[string]*simulations.MockerConfig { + configs := make(map[string]*simulations.MockerConfig) + + defaultCfg := simulations.DefaultMockerConfig() + defaultCfg.Id = "start-stop" + defaultCfg.Description = "Starts and Stops nodes in go routines" + defaultCfg.Mocker = startStopMocker + + bootNetworkCfg := simulations.DefaultMockerConfig() + bootNetworkCfg.Id = "bootNet" + bootNetworkCfg.Description = "Only boots up all nodes in the config" + bootNetworkCfg.Mocker = bootMocker + + randomNodesCfg := simulations.DefaultMockerConfig() + randomNodesCfg.Id = "randomNodes" + randomNodesCfg.Description = "Boots nodes and then starts and stops some picking randomly" + randomNodesCfg.Mocker = randomMocker + + configs[defaultCfg.Id] = defaultCfg + configs[bootNetworkCfg.Id] = bootNetworkCfg + configs[randomNodesCfg.Id] = randomNodesCfg + + return configs +} + +func setupMocker(net *simulations.Network) []*adapters.NodeId { conf := net.Config() conf.DefaultService = "overlay" @@ -123,6 +148,49 @@ func mocker(net *simulations.Network) { } } + return ids +} + +func bootMocker(net *simulations.Network) { + setupMocker(net) +} + +func randomMocker(net *simulations.Network) { + ids := setupMocker(net) + + for { + var lowid, highid int + randWait := rand.Intn(5000) + 1000 + rand1 := rand.Intn(9) + rand2 := rand.Intn(9) + if rand1 < rand2 { + lowid = rand1 + highid = rand2 + } else if rand1 > rand2 { + highid = rand1 + lowid = rand2 + } else { + if rand1 == 0 { + rand2 = 9 + } else if rand1 == 9 { + rand1 = 0 + } + } + for i := lowid; i < highid; i++ { + log.Debug(fmt.Sprintf("node %v shutting down", ids[i])) + net.Stop(ids[i]) + go func(id *adapters.NodeId) { + time.Sleep(time.Duration(randWait) * time.Millisecond) + net.Start(id) + }(ids[i]) + time.Sleep(time.Duration(randWait) * time.Millisecond) + } + } +} + +func startStopMocker(net *simulations.Network) { + ids := setupMocker(net) + for i, id := range ids { n := 3000 + i*1000 go func(id *adapters.NodeId) { @@ -154,9 +222,12 @@ func main() { } adapters.RegisterServices(services) + mockers := createMockers() + config := &simulations.ServerConfig{ - NewAdapter: func() adapters.NodeAdapter { return adapters.NewSimAdapter(services) }, - Mocker: mocker, + NewAdapter: func() adapters.NodeAdapter { return adapters.NewSimAdapter(services) }, + DefaultMockerId: "start-stop", + Mockers: mockers, } log.Info("starting simulation server on 0.0.0.0:8888...")