func TestRpc(test *testing.T) { ctrl := gomock.NewController(test) defer ctrl.Finish() store := mock_state.NewMockStore(ctrl) store.EXPECT().Read("states", "something", gomock.Any()).Return(fakeErr) store.EXPECT().Write("states", "something", gomock.Any()).Return(nil) local, err := state.NewLocalState("something", "wherever", "//here", store) if err != nil { test.Log(err) test.FailNow() } _, err = local.ExposeRPCEndpoint("tcp", "127.0.0.1:1234") if err != nil { test.Log(err) test.FailNow() } // I don't know why this causes the tests to fail // defer listen.Close() client := state.NewRemoteState("tcp", "127.0.0.1:1234", time.Second) testState(client, store, test) // now for tests specific to remote states err = client.SetDBRole("testing") if err == nil { test.Log("should not have been able to update the db state from remote") test.Fail() } if client.Location() != "127.0.0.1:1234" { test.Log("wrong location was returned") test.Fail() } }
func main() { if len(os.Args) != 2 { fmt.Println("Missing required config file!") fmt.Println("Please, run yoke with configuration file as argument (e.g. $ yoke /etc/yoke/yoke.ini)") os.Exit(1) } config.Init(os.Args[1]) config.ConfigurePGConf("0.0.0.0", config.Conf.PGPort) store, err := scribble.New(config.Conf.StatusDir, config.Log) if err != nil { config.Log.Fatal("Scribble did not setup correctly: %v", err) os.Exit(1) } location := fmt.Sprintf("%v:%d", config.Conf.AdvertiseIp, config.Conf.AdvertisePort) me, err := state.NewLocalState(config.Conf.Role, location, config.Conf.DataDir, store) if err != nil { config.Log.Fatal("Failed to set local state: %v", err) os.Exit(1) } me.ExposeRPCEndpoint("tcp", location) var other state.State var host string switch config.Conf.Role { case "primary": location := config.Conf.Secondary other = state.NewRemoteState("tcp", location, time.Second) host, _, err = net.SplitHostPort(location) if err != nil { config.Log.Fatal("Failed to split host:port for primary node: %v", err) os.Exit(1) } case "secondary": location := config.Conf.Primary other = state.NewRemoteState("tcp", location, time.Second) host, _, err = net.SplitHostPort(location) if err != nil { config.Log.Fatal("Failed to split host:port for secondary node: %v", err) os.Exit(1) } default: // nothing as the monitor does not need to monitor anything // the monitor just acts as a secondary mode of communication in network // splits } mon := state.NewRemoteState("tcp", config.Conf.Monitor, time.Second) var perform monitor.Performer finished := make(chan error) if other != nil { perform = monitor.NewPerformer(me, other, config.Conf) if err := perform.Initialize(); err != nil { config.Log.Fatal("Failed to initialize database: %v", err) os.Exit(1) } if err := config.ConfigureHBAConf(host); err != nil { config.Log.Fatal("Failed to configure pg_hba.conf file: %v", err) os.Exit(1) } if err := config.ConfigurePGConf("0.0.0.0", config.Conf.PGPort); err != nil { config.Log.Fatal("Failed to configure postgresql.conf file: %v", err) os.Exit(1) } if err := perform.Start(); err != nil { config.Log.Fatal("Failed to start postgres: %v", err) os.Exit(1) } go func() { decide := monitor.NewDecider(me, other, mon, perform) decide.Loop(time.Second * 2) }() go func() { err := perform.Loop() if err != nil { finished <- err } // how do I stop the decide loop? close(finished) }() } // signal Handle signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, os.Kill, syscall.SIGQUIT, syscall.SIGALRM) // Block until a signal is received. for { select { case err := <-finished: if err != nil { config.Log.Fatal("The performer is finished, something triggered a stop: %v", err) os.Exit(1) } config.Log.Info("the database was shut down") return case signal := <-signals: switch signal { case syscall.SIGINT, os.Kill, syscall.SIGQUIT, syscall.SIGTERM: config.Log.Info("shutting down") if perform != nil { // stop the database, then wait for it to be stopped config.Log.Info("shutting down the database") perform.Stop() perform = nil config.Log.Info("waiting for the database") } else { return } case syscall.SIGALRM: config.Log.Info("Printing Stack Trace") stacktrace := make([]byte, 8192) length := runtime.Stack(stacktrace, true) fmt.Println(string(stacktrace[:length])) } } } }
func TestBounce(test *testing.T) { ctrl := gomock.NewController(test) defer ctrl.Finish() store := mock_state.NewMockStore(ctrl) store.EXPECT().Read("states", "here", gomock.Any()).Return(fakeErr) store.EXPECT().Write("states", "here", gomock.Any()).Return(nil) local, err := state.NewLocalState("here", "right here", "//other", store) if err != nil { test.Log(err) test.FailNow() } listen, err := local.ExposeRPCEndpoint("tcp", "127.0.0.1:2345") if err != nil { test.Log(err) test.FailNow() } defer listen.Close() store.EXPECT().Read("states", "something", gomock.Any()).Return(fakeErr) store.EXPECT().Write("states", "something", gomock.Any()).Return(nil) remote, err := state.NewLocalState("something", "wherever", "//here", store) if err != nil { test.Log(err) test.FailNow() } testState(remote, store, test) test.Logf("now for the remote") // this needs to be reset remote.SetSynced(false) listen1, err := remote.ExposeRPCEndpoint("tcp", "127.0.0.1:3456") if err != nil { test.Log(err) test.FailNow() } defer listen1.Close() client := state.NewRemoteState("tcp", "127.0.0.1:2345", time.Second) bounced := client.Bounce("127.0.0.1:3456") testState(bounced, store, test) // now for tests specific to remote states err = bounced.SetDBRole("testing") if err == nil { test.Log("should not have been able to update the db state from remote") test.Fail() } if bounced.Location() != "127.0.0.1:3456" { test.Log("wrong location was returned") test.Fail() } }