From bd466a29680c619b65848bd0915e4a2da04fe17a Mon Sep 17 00:00:00 2001 From: Aleksey Shatunov Date: Thu, 27 Jun 2019 00:13:19 +0300 Subject: [PATCH 1/5] refactoring --- .gitignore | 3 + README.md | 32 ++-- build/docker-compose.yml | 67 ++++++++ build/sentinel1.conf | 14 ++ build/sentinel2.conf | 14 ++ build/sentinel3.conf | 14 ++ cmd/config/config.go | 36 ++++ cmd/main.go | 41 +++++ cmd/resolver/factory.go | 39 +++++ cmd/resolver/resolver.go | 37 ++++ cmd/server/server.go | 98 +++++++++++ cmd/server/shutdown.go | 52 ++++++ sentinel_tunnelling_client.go | 125 -------------- st_logger/st_logger.go | 51 ------ .../st_sentinel_connection.go | 158 ------------------ 15 files changed, 431 insertions(+), 350 deletions(-) create mode 100644 build/docker-compose.yml create mode 100755 build/sentinel1.conf create mode 100755 build/sentinel2.conf create mode 100755 build/sentinel3.conf create mode 100644 cmd/config/config.go create mode 100644 cmd/main.go create mode 100644 cmd/resolver/factory.go create mode 100644 cmd/resolver/resolver.go create mode 100644 cmd/server/server.go create mode 100644 cmd/server/shutdown.go delete mode 100644 sentinel_tunnelling_client.go delete mode 100644 st_logger/st_logger.go delete mode 100644 st_sentinel_connection/st_sentinel_connection.go diff --git a/.gitignore b/.gitignore index e2b9ca4..a9e1410 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ _testmain.go sentinel_tunnel log.txt commit.txt + +.idea/ +sentinel_tunnel_configuration.json \ No newline at end of file diff --git a/README.md b/README.md index 1527552..326136b 100644 --- a/README.md +++ b/README.md @@ -45,20 +45,21 @@ For example, the following config file contains two Sentinel addresses and two d ```json { - "Sentinels_addresses_list":[ - "node1.local:8001", - "node2.local:8001" - ], - "Databases":[ - { - "Name":"db1", - "Local_port":"12345" - }, - { - "Name":"db2", - "Local_port":"12346" - } - ] + "sentinels": [ + "127.0.0.1:26381", + "127.0.0.1:26382", + "127.0.0.1:26383" + ], + "databases": [ + { + "name": "my_redis_master", + "port": 36381 + }, + { + "name": "my_redis_master2", + "port": 36382 + } + ] } ``` @@ -66,9 +67,8 @@ For example, the following config file contains two Sentinel addresses and two d In order to run `sentinel_tunnel`: ```bash -$ ./sentinel_tunnel +$ ./sentinel_tunnel ``` -Set `log_file_path` to `/dev/null` for no logs. ## License diff --git a/build/docker-compose.yml b/build/docker-compose.yml new file mode 100644 index 0000000..4cd68b2 --- /dev/null +++ b/build/docker-compose.yml @@ -0,0 +1,67 @@ +version: '2.1' +services: + + redis1: + image: redis:3.2-alpine + ports: + - 6381:6379 + networks: + testnet: + ipv4_address: 172.22.1.10 + + sentinel1: + image: redis:3.2-alpine + ports: + - 26381:26379 + volumes: + - ./sentinel1.conf:/etc/sentinel.conf + command: redis-server /etc/sentinel.conf --sentinel + networks: + testnet: + ipv4_address: 172.22.1.11 + + redis2: + image: redis:3.2-alpine + ports: + - 6382:6379 + networks: + testnet: + ipv4_address: 172.22.1.20 + + sentinel2: + image: redis:3.2-alpine + ports: + - 26382:26379 + volumes: + - ./sentinel2.conf:/etc/sentinel.conf + command: redis-server /etc/sentinel.conf --sentinel + networks: + testnet: + ipv4_address: 172.22.1.21 + + redis3: + image: redis:3.2-alpine + ports: + - 6383:6379 + networks: + testnet: + ipv4_address: 172.22.1.30 + + sentinel3: + image: redis:3.2-alpine + ports: + - 26383:26379 + volumes: + - ./sentinel3.conf:/etc/sentinel.conf + command: redis-server /etc/sentinel.conf --sentinel + networks: + testnet: + ipv4_address: 172.22.1.31 + +networks: + testnet: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.22.1.0/24 \ No newline at end of file diff --git a/build/sentinel1.conf b/build/sentinel1.conf new file mode 100755 index 0000000..7908a20 --- /dev/null +++ b/build/sentinel1.conf @@ -0,0 +1,14 @@ +sentinel myid 6f45f9b7c4c2af2cb99cb00150dab6073b006918 +sentinel monitor my_redis_master 172.22.1.20 6379 3 +sentinel down-after-milliseconds my_redis_master 3000 +sentinel failover-timeout my_redis_master 10000 +# Generated by CONFIG REWRITE +port 26379 +dir "/data" +sentinel config-epoch my_redis_master 3 +sentinel leader-epoch my_redis_master 3 +sentinel known-slave my_redis_master 172.22.1.10 6379 +sentinel known-slave my_redis_master 172.22.1.30 6379 +sentinel known-sentinel my_redis_master 172.22.1.31 26379 d42bdac9dc1957e80284f454cc7731e96c432d11 +sentinel known-sentinel my_redis_master 172.22.1.21 26379 250456d4cda480fe092f2eeb5ca5dbc95fbe831d +sentinel current-epoch 3 diff --git a/build/sentinel2.conf b/build/sentinel2.conf new file mode 100755 index 0000000..7e62020 --- /dev/null +++ b/build/sentinel2.conf @@ -0,0 +1,14 @@ +sentinel myid 250456d4cda480fe092f2eeb5ca5dbc95fbe831d +sentinel monitor my_redis_master 172.22.1.20 6379 3 +sentinel down-after-milliseconds my_redis_master 3000 +sentinel failover-timeout my_redis_master 10000 +sentinel config-epoch my_redis_master 3 +# Generated by CONFIG REWRITE +port 26379 +dir "/data" +sentinel leader-epoch my_redis_master 3 +sentinel known-slave my_redis_master 172.22.1.10 6379 +sentinel known-slave my_redis_master 172.22.1.30 6379 +sentinel known-sentinel my_redis_master 172.22.1.11 26379 6f45f9b7c4c2af2cb99cb00150dab6073b006918 +sentinel known-sentinel my_redis_master 172.22.1.31 26379 d42bdac9dc1957e80284f454cc7731e96c432d11 +sentinel current-epoch 3 diff --git a/build/sentinel3.conf b/build/sentinel3.conf new file mode 100755 index 0000000..f19f80b --- /dev/null +++ b/build/sentinel3.conf @@ -0,0 +1,14 @@ +sentinel myid d42bdac9dc1957e80284f454cc7731e96c432d11 +sentinel monitor my_redis_master 172.22.1.20 6379 3 +sentinel down-after-milliseconds my_redis_master 3000 +sentinel failover-timeout my_redis_master 10000 +sentinel config-epoch my_redis_master 3 +# Generated by CONFIG REWRITE +port 26379 +dir "/data" +sentinel leader-epoch my_redis_master 3 +sentinel known-slave my_redis_master 172.22.1.10 6379 +sentinel known-slave my_redis_master 172.22.1.30 6379 +sentinel known-sentinel my_redis_master 172.22.1.11 26379 6f45f9b7c4c2af2cb99cb00150dab6073b006918 +sentinel known-sentinel my_redis_master 172.22.1.21 26379 250456d4cda480fe092f2eeb5ca5dbc95fbe831d +sentinel current-epoch 3 diff --git a/cmd/config/config.go b/cmd/config/config.go new file mode 100644 index 0000000..a0b1a80 --- /dev/null +++ b/cmd/config/config.go @@ -0,0 +1,36 @@ +package config + +import ( + "encoding/json" + "github.com/rs/zerolog/log" + "io/ioutil" +) + +type Config struct { + Sentinels []string `json:"sentinels"` + Databases []*DatabaseConfig `json:"databases"` +} + +type DatabaseConfig struct { + Name string `json:"name"` + Port uint16 `json:"port"` +} + +func CreateFromFile(path string) (*Config, error) { + b, err := ioutil.ReadFile(path) + if err != nil { + log.Error().Err(err).Msgf("read config file: %s", path) + + return nil, err + } + + conf := &Config{} + err = json.Unmarshal(b, conf) + if err != nil { + log.Error().Err(err).Msgf("parse config file: %s", path) + + return nil, err + } + + return conf, err +} diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..6c20cf8 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "github.com/DivPro/sentinel_tunnel/cmd/config" + "github.com/DivPro/sentinel_tunnel/cmd/resolver" + "github.com/DivPro/sentinel_tunnel/cmd/server" + "github.com/rs/zerolog/log" + "os" +) + +func main() { + if len(os.Args) < 3 { + fmt.Println("usage : sentinel_tunnel ") + return + } + + conf, err := config.CreateFromFile(os.Args[1]) + if err != nil { + log.Fatal().Err(err).Msg("init config") + } + + sentinels, err := resolver.CreateSentinels(conf.Sentinels) + if err != nil { + log.Fatal().Err(err).Msg("connect to sentinels") + } + srv := server.NewServer( + resolver.NewResolver(sentinels), + conf.Databases, + ) + go func() { + err := srv.Start() + if err != nil { + log.Fatal().Err(err).Msg("starting server") + } + }() + + ctx := server.GetShutdownCtx() + <-ctx.Done() + srv.Stop() +} diff --git a/cmd/resolver/factory.go b/cmd/resolver/factory.go new file mode 100644 index 0000000..db3e30e --- /dev/null +++ b/cmd/resolver/factory.go @@ -0,0 +1,39 @@ +package resolver + +import ( + "errors" + "github.com/go-redis/redis" + "github.com/rs/zerolog/log" +) + +func CreateSentinels(addrs []string) ([]*redis.SentinelClient, error) { + sentinels := make([]*redis.SentinelClient, 0, len(addrs)) + for _, addr := range addrs { + sentinel, err := createSentinel(addr) + if err != nil { + continue + } + sentinels = append(sentinels, sentinel) + } + if len(sentinels) == 0 { + return nil, errors.New("error connecting to all sentinels") + } + + return sentinels, nil +} + +func createSentinel(addr string) (*redis.SentinelClient, error) { + sentinel := redis.NewSentinelClient(&redis.Options{ + Addr: addr, + }) + + err := sentinel.Ping().Err() + if err != nil { + log.Error().Err(err).Msgf("error connecting to sentinel: %s", addr) + + return nil, err + } + log.Debug().Msgf("connected to sentinel: %s", addr) + + return sentinel, nil +} diff --git a/cmd/resolver/resolver.go b/cmd/resolver/resolver.go new file mode 100644 index 0000000..edcf179 --- /dev/null +++ b/cmd/resolver/resolver.go @@ -0,0 +1,37 @@ +package resolver + +import ( + "github.com/go-redis/redis" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + "strings" +) + +type Resolver interface { + Resolve(dbName string) (string, error) +} + +type resolver struct { + sentinels []*redis.SentinelClient +} + +func NewResolver(sentinels []*redis.SentinelClient) Resolver { + return &resolver{sentinels: sentinels} +} + +func (r *resolver) Resolve(dbName string) (string, error) { + for _, sentinel := range r.sentinels { + result, err := sentinel.GetMasterAddrByName(dbName).Result() + if err != nil { + continue + } + + ip := strings.Join(result, ":") + + log.Info().Msgf("'%s' resolved to master: %s", dbName, ip) + + return ip, nil + } + + return "", errors.New("all sentinels failed") +} diff --git a/cmd/server/server.go b/cmd/server/server.go new file mode 100644 index 0000000..d9b0d9b --- /dev/null +++ b/cmd/server/server.go @@ -0,0 +1,98 @@ +package server + +import ( + "fmt" + "github.com/DivPro/sentinel_tunnel/cmd/config" + "github.com/DivPro/sentinel_tunnel/cmd/resolver" + "github.com/rs/zerolog/log" + "golang.org/x/sync/errgroup" + "io" + "net" +) + +type Server interface { + Start() error + Stop() +} + +type server struct { + resolver resolver.Resolver + databases []*config.DatabaseConfig + listeners []net.Listener +} + +func NewServer(resolver resolver.Resolver, databases []*config.DatabaseConfig) Server { + return &server{ + resolver: resolver, + databases: databases, + } +} + +func (s *server) Start() error { + var eg errgroup.Group + fn := func(db *config.DatabaseConfig) func() error { + return func() error { + return s.startDatabase(db) + } + } + for _, db := range s.databases { + eg.Go(fn(db)) + } + + return eg.Wait() +} + +func (s *server) Stop() { + for _, listener := range s.listeners { + _ = listener.Close() + } +} + +func (s *server) startDatabase(conf *config.DatabaseConfig) error { + listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", conf.Port)) + if err != nil { + log.Error().Err(err).Msgf("error listening port: %d", conf.Port) + return err + } + + log.Info().Msgf("listening started '%s' on port %d", conf.Name, conf.Port) + s.listeners = append(s.listeners, listener) + + for { + conn, err := listener.Accept() + if err != nil { + log.Error().Err(err).Msgf("error accepting connection to: %s on port %d", conf.Name, conf.Port) + continue + } + + go s.handleConnection(conn, conf.Name) + } +} + +func (s *server) handleConnection(conn net.Conn, dbName string) { + log.Debug().Msgf("resolving: %s", dbName) + dbAddr, err := s.resolver.Resolve(dbName) + if err != nil { + log.Error().Err(err).Msgf("failed resolving db: %s", dbName) + _ = conn.Close() + return + } + + dbConn, err := net.Dial("tcp", dbAddr) + if err != nil { + log.Error().Err(err).Msgf("error tunneling to: %s", dbName) + _ = conn.Close() + return + } + go createTunnelling(conn, dbConn) + go createTunnelling(dbConn, conn) +} + +func createTunnelling(conn1 net.Conn, conn2 net.Conn) { + _, err := io.Copy(conn1, conn2) + if err != nil { + log.Error().Err(err).Msg("tunneling") + } + _ = conn1.Close() + _ = conn2.Close() +} diff --git a/cmd/server/shutdown.go b/cmd/server/shutdown.go new file mode 100644 index 0000000..e2b915e --- /dev/null +++ b/cmd/server/shutdown.go @@ -0,0 +1,52 @@ +package server + +import ( + "context" + "os" + "os/signal" + "sync" + "syscall" + + "github.com/rs/zerolog/log" +) + +var ( + ctx, cancelFunc = context.WithCancel(context.Background()) + gc sync.Once + catcher chan os.Signal +) + +func init() { + catcher = make(chan os.Signal, 1) + signal.Notify(catcher, syscall.SIGINT, syscall.SIGTERM) +} + +func GetShutdownCtx() context.Context { + gc.Do(func() { + log.Info().Msg("launch catch gorutine") + go launchCatcher() + }) + + return ctx +} + +func Shutdown() { + cancelFunc() +} + +func launchCatcher() { + go func() { + for sig := range catcher { + switch sig { + case syscall.SIGTERM: + log.Info().Msg("Got SIGTERM stopping application") + cancelFunc() + case syscall.SIGINT: + log.Info().Msg("Got SIGINT stopping application") + cancelFunc() + } + + log.Info().Msg("catch signal") + } + }() +} diff --git a/sentinel_tunnelling_client.go b/sentinel_tunnelling_client.go deleted file mode 100644 index cb0c883..0000000 --- a/sentinel_tunnelling_client.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - // "bufio" - "encoding/json" - "fmt" - "github.com/RedisLabs/sentinel_tunnel/st_logger" - "github.com/RedisLabs/sentinel_tunnel/st_sentinel_connection" - "io" - "io/ioutil" - "net" - "os" - "time" -) - -type SentinelTunnellingDbConfig struct { - Name string - Local_port string -} - -type SentinelTunnellingConfiguration struct { - Sentinels_addresses_list []string - Databases []SentinelTunnellingDbConfig -} - -type SentinelTunnellingClient struct { - configuration SentinelTunnellingConfiguration - sentinel_connection *st_sentinel_connection.Sentinel_connection -} - -type get_db_address_by_name_function func(db_name string) (string, error) - -func NewSentinelTunnellingClient(config_file_location string) *SentinelTunnellingClient { - data, err := ioutil.ReadFile(config_file_location) - if err != nil { - st_logger.WriteLogMessage(st_logger.FATAL, "an error has occur during configuration read", - err.Error()) - } - - Tunnelling_client := SentinelTunnellingClient{} - err = json.Unmarshal(data, &(Tunnelling_client.configuration)) - if err != nil { - st_logger.WriteLogMessage(st_logger.FATAL, "an error has occur during configuration read,", - err.Error()) - } - - Tunnelling_client.sentinel_connection, err = - st_sentinel_connection.NewSentinelConnection(Tunnelling_client.configuration.Sentinels_addresses_list) - if err != nil { - st_logger.WriteLogMessage(st_logger.FATAL, "an error has occur, ", - err.Error()) - } - - st_logger.WriteLogMessage(st_logger.INFO, "done initializing Tunnelling") - - return &Tunnelling_client -} - -func createTunnelling(conn1 net.Conn, conn2 net.Conn) { - io.Copy(conn1, conn2) - conn1.Close() - conn2.Close() -} - -func handleConnection(c net.Conn, db_name string, - get_db_address_by_name get_db_address_by_name_function) { - db_address, err := get_db_address_by_name(db_name) - if err != nil { - st_logger.WriteLogMessage(st_logger.ERROR, "cannot get db address for ", db_name, - ",", err.Error()) - c.Close() - return - } - db_conn, err := net.Dial("tcp", db_address) - if err != nil { - st_logger.WriteLogMessage(st_logger.ERROR, "cannot connect to db ", db_name, - ",", err.Error()) - c.Close() - return - } - go createTunnelling(c, db_conn) - go createTunnelling(db_conn, c) -} - -func handleSigleDbConnections(listening_port string, db_name string, - get_db_address_by_name get_db_address_by_name_function) { - - listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%s", listening_port)) - if err != nil { - st_logger.WriteLogMessage(st_logger.FATAL, "cannot listen to port ", - listening_port, err.Error()) - } - - st_logger.WriteLogMessage(st_logger.INFO, "listening on port ", listening_port, - " for connections to database: ", db_name) - for { - conn, err := listener.Accept() - if err != nil { - st_logger.WriteLogMessage(st_logger.FATAL, "cannot accept connections on port ", - listening_port, err.Error()) - } - go handleConnection(conn, db_name, get_db_address_by_name) - } - -} - -func (st_client *SentinelTunnellingClient) Start() { - for _, db_conf := range st_client.configuration.Databases { - go handleSigleDbConnections(db_conf.Local_port, db_conf.Name, - st_client.sentinel_connection.GetAddressByDbName) - } -} - -func main() { - if len(os.Args) < 3 { - fmt.Println("usage : sentinel_tunnel ") - return - } - st_logger.InitializeLogger(os.Args[2]) - st_client := NewSentinelTunnellingClient(os.Args[1]) - st_client.Start() - for { - time.Sleep(1000 * time.Millisecond) - } -} diff --git a/st_logger/st_logger.go b/st_logger/st_logger.go deleted file mode 100644 index 11593a2..0000000 --- a/st_logger/st_logger.go +++ /dev/null @@ -1,51 +0,0 @@ -package st_logger - -import ( - "bytes" - "log" - "os" -) - -var logger *log.Logger - -const ( - INFO = iota - ERROR = iota - FATAL = iota - DEBUG = iota -) - -func InitializeLogger(log_file_path string) { - file, err := os.OpenFile(log_file_path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - log.Fatalln("Failed to open log file", log_file_path, ":", err) - } - logger = log.New(file, - "", - log.Ldate|log.Ltime) -} - -func WriteLogMessage(level int, message ...string) { - var buffer bytes.Buffer - if level == INFO { - buffer.WriteString("info : ") - } else if level == ERROR { - buffer.WriteString("error : ") - } else if level == FATAL { - buffer.WriteString("fatal : ") - } else if level == FATAL { - buffer.WriteString("debug : ") - } - - for _, m := range message { - buffer.WriteString(m) - buffer.WriteString(" ") - } - - logger.Println(buffer.String()) - - if level == FATAL { - logger.Println("fatal error occure commiting suicide") - os.Exit(1) - } -} diff --git a/st_sentinel_connection/st_sentinel_connection.go b/st_sentinel_connection/st_sentinel_connection.go deleted file mode 100644 index bd09e99..0000000 --- a/st_sentinel_connection/st_sentinel_connection.go +++ /dev/null @@ -1,158 +0,0 @@ -package st_sentinel_connection - -import ( - "bufio" - "errors" - "fmt" - "net" - "strconv" - "time" -) - -type Get_master_addr_reply struct { - reply string - err error -} - -type Sentinel_connection struct { - sentinels_addresses []string - current_sentinel_connection net.Conn - reader *bufio.Reader - writer *bufio.Writer - get_master_address_by_name_reply chan *Get_master_addr_reply - get_master_address_by_name chan string -} - -const ( - client_closed = true - client_not_closed = false -) - -func (c *Sentinel_connection) parseResponse() (request []string, err error, is_client_closed bool) { - var ret []string - buf, _, e := c.reader.ReadLine() - if e != nil { - return nil, errors.New("failed read line from client"), client_closed - } - if len(buf) == 0 { - return nil, errors.New("failed read line from client"), client_closed - } - if buf[0] != '*' { - return nil, errors.New("first char in mbulk is not *"), client_not_closed - } - mbulk_size, _ := strconv.Atoi(string(buf[1:])) - if mbulk_size == -1 { - return nil, errors.New("null request"), client_not_closed - } - ret = make([]string, mbulk_size) - for i := 0; i < mbulk_size; i++ { - buf1, _, e1 := c.reader.ReadLine() - if e1 != nil { - return nil, errors.New("failed read line from client"), client_closed - } - if len(buf1) == 0 { - return nil, errors.New("failed read line from client"), client_closed - } - if buf1[0] != '$' { - return nil, errors.New("first char in bulk is not $"), client_not_closed - } - bulk_size, _ := strconv.Atoi(string(buf1[1:])) - buf2, _, e2 := c.reader.ReadLine() - if e2 != nil { - return nil, errors.New("failed read line from client"), client_closed - } - bulk := string(buf2) - if len(bulk) != bulk_size { - return nil, errors.New("wrong bulk size"), client_not_closed - } - ret[i] = bulk - } - return ret, nil, client_not_closed -} - -func (c *Sentinel_connection) getMasterAddrByNameFromSentinel(db_name string) (addr []string, returned_err error, is_client_closed bool) { - c.writer.WriteString("*3\r\n") - c.writer.WriteString("$8\r\n") - c.writer.WriteString("sentinel\r\n") - c.writer.WriteString("$23\r\n") - c.writer.WriteString("get-master-addr-by-name\r\n") - c.writer.WriteString(fmt.Sprintf("$%d\r\n", len(db_name))) - c.writer.WriteString(db_name) - c.writer.WriteString("\r\n") - c.writer.Flush() - - return c.parseResponse() -} - -func (c *Sentinel_connection) retrieveAddressByDbName() { - for db_name := range c.get_master_address_by_name { - addr, err, is_client_closed := c.getMasterAddrByNameFromSentinel(db_name) - if err != nil { - fmt.Println("err: ", err.Error()) - if !is_client_closed { - c.get_master_address_by_name_reply <- &Get_master_addr_reply{ - reply: "", - err: errors.New("failed to retrieve db name from the sentinel, db_name:" + db_name), - } - } - if !c.reconnectToSentinel() { - c.get_master_address_by_name_reply <- &Get_master_addr_reply{ - reply: "", - err: errors.New("failed to connect to any of the sentinel services"), - } - } - continue - } - c.get_master_address_by_name_reply <- &Get_master_addr_reply{ - reply: net.JoinHostPort(addr[0], addr[1]), - err: nil, - } - } -} - -func (c *Sentinel_connection) reconnectToSentinel() bool { - for _, sentinelAddr := range c.sentinels_addresses { - - if c.current_sentinel_connection != nil { - c.current_sentinel_connection.Close() - c.reader = nil - c.writer = nil - c.current_sentinel_connection = nil - } - - var err error - c.current_sentinel_connection, err = net.DialTimeout("tcp", sentinelAddr, 300*time.Millisecond) - if err == nil { - c.reader = bufio.NewReader(c.current_sentinel_connection) - c.writer = bufio.NewWriter(c.current_sentinel_connection) - return true - } - fmt.Println(err.Error()) - } - return false -} - -func (c *Sentinel_connection) GetAddressByDbName(name string) (string, error) { - c.get_master_address_by_name <- name - reply := <-c.get_master_address_by_name_reply - return reply.reply, reply.err -} - -func NewSentinelConnection(addresses []string) (*Sentinel_connection, error) { - connection := Sentinel_connection{ - sentinels_addresses: addresses, - get_master_address_by_name: make(chan string), - get_master_address_by_name_reply: make(chan *Get_master_addr_reply), - current_sentinel_connection: nil, - reader: nil, - writer: nil, - } - - if !connection.reconnectToSentinel() { - return nil, errors.New("could not connect to any sentinels") - } - - go connection.retrieveAddressByDbName() - - return &connection, nil -} From 84a8e61bbb2758dab981fa5e680c55ebbe2a2e9b Mon Sep 17 00:00:00 2001 From: Aleksey Shatunov Date: Thu, 27 Jun 2019 00:30:49 +0300 Subject: [PATCH 2/5] configuration fix --- sentinel_tunnel_configuration_example.json | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/sentinel_tunnel_configuration_example.json b/sentinel_tunnel_configuration_example.json index 5f88c7c..04a65d1 100644 --- a/sentinel_tunnel_configuration_example.json +++ b/sentinel_tunnel_configuration_example.json @@ -1,16 +1,17 @@ { - "Sentinels_addresses_list":[ - "node1.local:8001", - "node2.local:8001" - ], - "Databases":[ - { - "Name":"db1", - "Local_port":"12345" - }, - { - "Name":"db2", - "Local_port":"12346" - } - ] + "sentinels": [ + "127.0.0.1:26381", + "127.0.0.1:26382", + "127.0.0.1:26383" + ], + "databases": [ + { + "name": "my_redis_master", + "port": 36381 + }, + { + "name": "my_redis_master2", + "port": 36382 + } + ] } \ No newline at end of file From 2feb629f8664b33ff3a598c300338bbd4ee1459f Mon Sep 17 00:00:00 2001 From: Shatunov Alexey Date: Thu, 27 Jun 2019 12:30:00 +0300 Subject: [PATCH 3/5] fixed os.Args check --- cmd/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index 6c20cf8..064c65a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -10,7 +10,7 @@ import ( ) func main() { - if len(os.Args) < 3 { + if len(os.Args) < 2 { fmt.Println("usage : sentinel_tunnel ") return } From f10362adbf6e927b5b4d7c8d2c95699b66d50baf Mon Sep 17 00:00:00 2001 From: Aleksey Shatunov Date: Sat, 6 Jul 2019 22:02:35 +0300 Subject: [PATCH 4/5] modules support --- cmd/resolver/factory.go | 6 ------ go.mod | 13 +++++++++++++ go.sum | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/cmd/resolver/factory.go b/cmd/resolver/factory.go index db3e30e..e36b761 100644 --- a/cmd/resolver/factory.go +++ b/cmd/resolver/factory.go @@ -27,12 +27,6 @@ func createSentinel(addr string) (*redis.SentinelClient, error) { Addr: addr, }) - err := sentinel.Ping().Err() - if err != nil { - log.Error().Err(err).Msgf("error connecting to sentinel: %s", addr) - - return nil, err - } log.Debug().Msgf("connected to sentinel: %s", addr) return sentinel, nil diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fe79442 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module github.com/DivPro/sentinel_tunnel + +go 1.12 + +require ( + github.com/go-redis/redis v6.15.2+incompatible + github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect + github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect + github.com/pkg/errors v0.8.1 + github.com/rs/zerolog v1.14.3 + golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c // indirect + golang.org/x/sync v0.0.0-20190423024810-112230192c58 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c2bd957 --- /dev/null +++ b/go.sum @@ -0,0 +1,26 @@ +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f h1:Jnx61latede7zDD3DiiP4gmNz33uK0U5HDUaF0a/HVQ= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.14.3 h1:4EGfSkR2hJDB0s3oFfrlPqjU1e4WLncergLil3nEKW0= +github.com/rs/zerolog v1.14.3/go.mod h1:3WXPzbXEEliJ+a6UFE4vhIxV8qR1EML6ngzP9ug4eYg= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c h1:Rx/HTKi09myZ25t1SOlDHmHOy/mKxNAcu0hP1oPX9qM= +golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc h1:N3zlSgxkefUH/ecsl37RWTkESTB026kmXzNly8TuZCI= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= From 14a1257054b3286176b222e9775830e29e27bd49 Mon Sep 17 00:00:00 2001 From: Shatunov Alexey Date: Mon, 8 Jul 2019 15:35:09 +0300 Subject: [PATCH 5/5] ping test --- build/docker-compose.yml | 0 build/sentinel1.conf | 12 ++++++------ build/sentinel2.conf | 12 ++++++------ build/sentinel3.conf | 10 +++++----- cmd/main_test.go | 18 ++++++++++++++++++ 5 files changed, 35 insertions(+), 17 deletions(-) mode change 100644 => 100755 build/docker-compose.yml create mode 100644 cmd/main_test.go diff --git a/build/docker-compose.yml b/build/docker-compose.yml old mode 100644 new mode 100755 diff --git a/build/sentinel1.conf b/build/sentinel1.conf index 7908a20..f03ca51 100755 --- a/build/sentinel1.conf +++ b/build/sentinel1.conf @@ -1,14 +1,14 @@ sentinel myid 6f45f9b7c4c2af2cb99cb00150dab6073b006918 -sentinel monitor my_redis_master 172.22.1.20 6379 3 +sentinel monitor my_redis_master 172.22.1.30 6379 3 sentinel down-after-milliseconds my_redis_master 3000 sentinel failover-timeout my_redis_master 10000 # Generated by CONFIG REWRITE port 26379 dir "/data" -sentinel config-epoch my_redis_master 3 -sentinel leader-epoch my_redis_master 3 +sentinel config-epoch my_redis_master 4 +sentinel leader-epoch my_redis_master 4 sentinel known-slave my_redis_master 172.22.1.10 6379 -sentinel known-slave my_redis_master 172.22.1.30 6379 -sentinel known-sentinel my_redis_master 172.22.1.31 26379 d42bdac9dc1957e80284f454cc7731e96c432d11 +sentinel known-slave my_redis_master 172.22.1.20 6379 sentinel known-sentinel my_redis_master 172.22.1.21 26379 250456d4cda480fe092f2eeb5ca5dbc95fbe831d -sentinel current-epoch 3 +sentinel known-sentinel my_redis_master 172.22.1.31 26379 d42bdac9dc1957e80284f454cc7731e96c432d11 +sentinel current-epoch 4 diff --git a/build/sentinel2.conf b/build/sentinel2.conf index 7e62020..9593e5e 100755 --- a/build/sentinel2.conf +++ b/build/sentinel2.conf @@ -1,14 +1,14 @@ sentinel myid 250456d4cda480fe092f2eeb5ca5dbc95fbe831d -sentinel monitor my_redis_master 172.22.1.20 6379 3 +sentinel monitor my_redis_master 172.22.1.30 6379 3 sentinel down-after-milliseconds my_redis_master 3000 sentinel failover-timeout my_redis_master 10000 -sentinel config-epoch my_redis_master 3 +sentinel config-epoch my_redis_master 4 # Generated by CONFIG REWRITE port 26379 dir "/data" -sentinel leader-epoch my_redis_master 3 +sentinel leader-epoch my_redis_master 4 +sentinel known-slave my_redis_master 172.22.1.20 6379 sentinel known-slave my_redis_master 172.22.1.10 6379 -sentinel known-slave my_redis_master 172.22.1.30 6379 -sentinel known-sentinel my_redis_master 172.22.1.11 26379 6f45f9b7c4c2af2cb99cb00150dab6073b006918 sentinel known-sentinel my_redis_master 172.22.1.31 26379 d42bdac9dc1957e80284f454cc7731e96c432d11 -sentinel current-epoch 3 +sentinel known-sentinel my_redis_master 172.22.1.11 26379 6f45f9b7c4c2af2cb99cb00150dab6073b006918 +sentinel current-epoch 4 diff --git a/build/sentinel3.conf b/build/sentinel3.conf index f19f80b..ef52dd9 100755 --- a/build/sentinel3.conf +++ b/build/sentinel3.conf @@ -1,14 +1,14 @@ sentinel myid d42bdac9dc1957e80284f454cc7731e96c432d11 -sentinel monitor my_redis_master 172.22.1.20 6379 3 +sentinel monitor my_redis_master 172.22.1.30 6379 3 sentinel down-after-milliseconds my_redis_master 3000 sentinel failover-timeout my_redis_master 10000 -sentinel config-epoch my_redis_master 3 +sentinel config-epoch my_redis_master 4 # Generated by CONFIG REWRITE port 26379 dir "/data" -sentinel leader-epoch my_redis_master 3 +sentinel leader-epoch my_redis_master 4 sentinel known-slave my_redis_master 172.22.1.10 6379 -sentinel known-slave my_redis_master 172.22.1.30 6379 +sentinel known-slave my_redis_master 172.22.1.20 6379 sentinel known-sentinel my_redis_master 172.22.1.11 26379 6f45f9b7c4c2af2cb99cb00150dab6073b006918 sentinel known-sentinel my_redis_master 172.22.1.21 26379 250456d4cda480fe092f2eeb5ca5dbc95fbe831d -sentinel current-epoch 3 +sentinel current-epoch 4 diff --git a/cmd/main_test.go b/cmd/main_test.go new file mode 100644 index 0000000..48ba90e --- /dev/null +++ b/cmd/main_test.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + "github.com/go-redis/redis" + "testing" + "time" +) + +func TestServer(t *testing.T) { + cl := redis.NewClient(&redis.Options{ + Addr: "127.0.0.1:36381", + }) + for { + fmt.Println(cl.Ping().String()) + time.Sleep(time.Millisecond * 200) + } +}