diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..b3313b6 --- /dev/null +++ b/api/api.go @@ -0,0 +1,52 @@ +package api + +import ( + "github.com/Navid2zp/citus-failover/config" + "github.com/Navid2zp/citus-failover/logging" + "github.com/gin-gonic/gin" + "log" + "net/http" +) + +var logger *logging.Logger + +func initAPI() { + logger = logging.NewLogger("api") + if !config.Config.Settings.Debug { + gin.SetMode(gin.ReleaseMode) + } +} + +func adminMiddleware(c *gin.Context) { + secret := c.Request.Header.Get("Secret") + if secret == "" { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": ErrCodeSecretMissing}) + return + } + if secret != config.Config.API.Secret { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": ErrCodeInvalidSecret}) + return + } + c.Next() +} + +func Serve() { + initAPI() + + router := gin.Default() + v1 := router.Group("/v1", adminMiddleware) + + { + v1.GET("/workers", getPrimaryWorkers) + v1.GET("/coordinator", getPrimaryCoordinator) + v1.GET("/coordinators", getAllCoordinators) + v1.GET("/nodes", getNodes) + } + + log.Println("Starting api on port", config.Config.API.Port, "...") + + err := router.Run(":" + config.Config.API.Port) + if err != nil { + logger.APIStartFailed(err) + } +} diff --git a/api/handlers.go b/api/handlers.go new file mode 100644 index 0000000..0eb32db --- /dev/null +++ b/api/handlers.go @@ -0,0 +1,69 @@ +package api + +import ( + "github.com/Navid2zp/citus-failover/core" + "github.com/gin-gonic/gin" + "net/http" +) + +const ( + ErrCodeServerError = "SERVER_ERROR" + ErrCodeSecretMissing = "SECRET_MISSING" + ErrCodeInvalidSecret = "INVALID_SECRET" +) + +func getPrimaryWorkers(c *gin.Context) { + workers, err := core.GetPrimaryWorkers() + if err != nil { + logger.GetWorkersFailed(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": ErrCodeServerError, + "message": "failed to get workers from coordinator", + }) + return + } + + c.JSON(http.StatusOK, workers) +} + +func getPrimaryCoordinator(c *gin.Context) { + coordinator, err := core.GetCoordinator() + if err != nil { + logger.GetCoordinatorFailed(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": ErrCodeServerError, + "message": "failed to get coordinator from monitor", + }) + return + } + + c.JSON(http.StatusOK, coordinator) +} + +func getAllCoordinators(c *gin.Context) { + coordinators, err := core.GetAllCoordinators() + if err != nil { + logger.GetCoordinatorFailed(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": ErrCodeServerError, + "message": "failed to get coordinators from monitor", + }) + return + } + + c.JSON(http.StatusOK, coordinators) +} + +func getNodes(c *gin.Context) { + nodes, err := core.GetNodes() + if err != nil { + logger.GetWorkersFailed(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "error": ErrCodeServerError, + "message": "failed to get nodes from monitor", + }) + return + } + + c.JSON(http.StatusOK, nodes) +} diff --git a/config.example.yml b/config.example.yml index b728e95..de75ca6 100644 --- a/config.example.yml +++ b/config.example.yml @@ -11,6 +11,7 @@ Coordinator: DBName: postgres Settings: CheckInterval: 2000 + Debug: false API: Enabled: true Port: 3002 diff --git a/config/config.go b/config/config.go index c08b6de..a45e9e5 100644 --- a/config/config.go +++ b/config/config.go @@ -21,14 +21,15 @@ type ServiceConfig struct { Formation string Username string Password string - DBName string + DBName string } Settings struct { - CheckInterval int + CheckInterval int + Debug bool } API struct { Enabled bool - Port int + Port string Secret string } } diff --git a/core/core.go b/core/core.go index fd55dd8..f56bdbc 100644 --- a/core/core.go +++ b/core/core.go @@ -7,48 +7,54 @@ import ( ) type Node struct { - FormationID string `db:"formationid"` - ID int `db:"nodeid"` - GroupID int `db:"groupid"` - Name string `db:"nodename"` - Host string `db:"nodehost"` - Port int `db:"nodeport"` - SysIdentifier string `db:"sysidentifier"` - GoalState string `db:"goalstate"` - ReportedState string `db:"reportedstate"` - ReportedPGIsRunning bool `db:"reportedpgisrunning"` - ReportedRepState string `db:"reportedrepstate"` - ReportTime time.Time `db:"reporttime"` - ReportedLSN string `db:"reportedlsn"` - WALReportTime time.Time `db:"walreporttime"` - Health int `db:"health"` - HealthCheckTime time.Time `db:"healthchecktime"` - StateChangeTime time.Time `db:"statechangetime"` - CandidatePriority int `db:"candidatepriority"` - ReplicationQuorum bool `db:"replicationquorum"` - NodeCluster string `db:"nodecluster"` - IsCoordinator bool `db:"-"` + FormationID string `db:"formationid" json:"formation_id"` + ID int `db:"nodeid" json:"id"` + GroupID int `db:"groupid" json:"group_id"` + Name string `db:"nodename" json:"name"` + Host string `db:"nodehost" json:"host"` + Port int `db:"nodeport" json:"port"` + SysIdentifier string `db:"sysidentifier" json:"sys_identifier"` + GoalState string `db:"goalstate" json:"goal_state"` + ReportedState string `db:"reportedstate" json:"reported_state"` + ReportedPGIsRunning bool `db:"reportedpgisrunning" json:"reported_pg_is_running"` + ReportedRepState string `db:"reportedrepstate" json:"reported_rep_state"` + ReportTime time.Time `db:"reporttime" json:"report_time"` + ReportedLSN string `db:"reportedlsn" json:"reported_lsn"` + WALReportTime time.Time `db:"walreporttime" json:"wal_report_time"` + Health int `db:"health" json:"health"` + HealthCheckTime time.Time `db:"healthchecktime" json:"health_check_time"` + StateChangeTime time.Time `db:"statechangetime" json:"state_change_time"` + CandidatePriority int `db:"candidatepriority" json:"candidate_priority"` + ReplicationQuorum bool `db:"replicationquorum" json:"replication_quorum"` + NodeCluster string `db:"nodecluster" json:"node_cluster"` + IsCoordinator bool `db:"-" json:"-"` } type Worker struct { - ID int `db:"nodeid"` - GroupID int `db:"groupid"` - Host string `db:"nodename"` - Port int `db:"nodeport"` - Rack string `db:"noderack"` - HasMetaData NullBool `db:"hasmetadata"` - Active bool `db:"isactive"` - Role string `db:"noderole"` - Cluster string `db:"nodecluster"` - MetaDataSynced NullBool `db:"metadatasynced"` - ShouldHaveShards bool `db:"shouldhaveshards"` + ID int `db:"nodeid" json:"id"` + GroupID int `db:"groupid" json:"group_id"` + Host string `db:"nodename" json:"host"` + Port int `db:"nodeport" json:"port"` + Rack string `db:"noderack" json:"rack"` + HasMetaData NullBool `db:"hasmetadata" json:"has_meta_data"` + Active bool `db:"isactive" json:"active"` + Role string `db:"noderole" json:"role"` + Cluster string `db:"nodecluster" json:"cluster"` + MetaDataSynced NullBool `db:"metadatasynced" json:"meta_data_synced"` + ShouldHaveShards bool `db:"shouldhaveshards" json:"should_have_shards"` } type Coordinator struct { - PrimaryNodeID int `db:"primary_node_id"` - Name string `db:"primary_name"` - Host string `db:"primary_host"` - Port int `db:"primary_port"` + PrimaryNodeID int `db:"primary_node_id" json:"primary_node_id"` + Name string `db:"primary_name" json:"name"` + Host string `db:"primary_host" json:"host"` + Port int `db:"primary_port" json:"port"` +} + +func GetNodes() ([]*Node, error) { + var nodes []*Node + err := monitorDB.Select(&nodes, `select * from pgautofailover.node`) + return nodes, err } func GetPrimaryWorkers() ([]*Worker, error) { @@ -76,6 +82,13 @@ func (w *Worker) updateCoordinator(newHost string, newPort int) error { return err } +func GetAllCoordinators() ([]*Node, error) { + var coordinators []*Node + err := monitorDB.Select(&coordinators, + `select * from pgautofailover.node where formationid = $1;`, config.Config.Coordinator.Formation) + return coordinators, err +} + func GetCoordinator() (*Coordinator, error) { var node Coordinator err := monitorDB.Get(&node, diff --git a/go.mod b/go.mod index f58f67e..08c957a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/Navid2zp/citus-failover go 1.16 require ( + github.com/gin-gonic/gin v1.7.1 // indirect github.com/jmoiron/sqlx v1.3.3 // indirect github.com/lib/pq v1.2.0 // indirect github.com/spf13/viper v1.7.1 // indirect diff --git a/go.sum b/go.sum index 58a7f43..0138fb5 100644 --- a/go.sum +++ b/go.sum @@ -68,6 +68,10 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8= +github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= @@ -75,6 +79,13 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= @@ -94,12 +105,15 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -164,6 +178,8 @@ github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -184,6 +200,8 @@ github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -192,6 +210,8 @@ github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRU github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -211,8 +231,10 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc= @@ -283,6 +305,10 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= @@ -309,6 +335,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -371,6 +399,8 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -441,6 +471,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/logging/api.go b/logging/api.go new file mode 100644 index 0000000..e7be517 --- /dev/null +++ b/logging/api.go @@ -0,0 +1,8 @@ +package logging + +import "go.uber.org/zap" + +func (l *Logger) APIStartFailed(err error) { + l.l.Error("failed to start api", + zap.String("service", l.service), zap.Error(err)) +} diff --git a/logging/core.go b/logging/core.go new file mode 100644 index 0000000..1d8edda --- /dev/null +++ b/logging/core.go @@ -0,0 +1,80 @@ +package logging + +import ( + "database/sql" + "fmt" + "go.uber.org/zap" +) + +func (l *Logger) MonitorInit() { + l.l.Info("monitoring initialized ...") +} + +func (l *Logger) NoCoordinatorFound() { + l.l.Error("no coordinator found! probably switching state, skipping ...", + zap.String("service", l.service)) +} + +func (l *Logger) CoordinatorChanged(oldHost, newHost string, oldPort, newPort int) { + l.l.Info("coordinator changed, connecting to new coordinator.", + zap.String("service", l.service), + zap.String("old-coordinator", fmt.Sprintf("%s:%d", oldHost, oldPort)), + zap.String("new-coordinator", fmt.Sprintf("%s:%d", newHost, newPort))) +} + +func (l *Logger) CoordinatorConnectionLost(host string, port int) { + l.l.Warn("coordinator connection lost, reconnecting ...", + zap.String("service", l.service), + zap.String("host", host), zap.Int("port", port)) +} + +func (l *Logger) CoordinatorConnectionFailed(host string, port int, err error) { + l.l.Error("connecting to coordinator failed!", + zap.String("service", l.service), + zap.String("host", host), zap.Int("port", port), zap.Error(err)) +} + +func (l *Logger) GetCoordinatorFailed(err error) { + l.l.Error("failed to get coordinator, skipping ...", + zap.String("service", l.service), zap.Error(err)) +} + +func (l *Logger) GetWorkersFailed(err error) { + if err == sql.ErrNoRows { + l.NoWorkersFound() + return + } + l.l.Error("failed to get workers!", + zap.String("service", l.service), zap.Error(err)) +} + +func (l *Logger) WorkerPrimaryCheckFailed(err error, workerID int) { + l.l.Error("failed to check if worker is primary!", + zap.String("service", l.service), zap.Error(err), zap.Int("worker-id", workerID)) +} + +func (l *Logger) WorkerStateChange(oldHost, newHost string, oldPort, newPort int) { + oldWorker := fmt.Sprintf("%s:%d", oldHost, oldPort) + newWorker := fmt.Sprintf("%s:%d", newHost, newPort) + l.l.Info("worker change detected, updating coordinator ...", + zap.String("service", l.service), + zap.String("old-worker", oldWorker), zap.String("new-worker", newWorker)) +} + +func (l *Logger) WorkerUpdated(oldHost, newHost string, oldPort, newPort int) { + oldWorker := fmt.Sprintf("%s:%d", oldHost, oldPort) + newWorker := fmt.Sprintf("%s:%d", newHost, newPort) + l.l.Info("worker updated", + zap.String("service", l.service), + zap.String("old-worker", oldWorker), zap.String("new-worker", newWorker)) +} + +func (l *Logger) WorkerUpdateFailed(err error) { + l.l.Error("failed to update worker in coordinator", + zap.String("service", l.service), zap.Error(err)) +} + +func (l *Logger) NoWorkersFound() { + l.l.Error("no workers found!", + zap.String("service", l.service)) +} diff --git a/logging/logger.go b/logging/logger.go index 0389e91..ac47870 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -1,8 +1,6 @@ package logging import ( - "database/sql" - "fmt" "go.uber.org/zap" ) @@ -23,76 +21,3 @@ func NewLogger(service string) *Logger { return &Logger{service, logger} } - -func (l *Logger) MonitorInit() { - l.l.Info("monitoring initialized ...") -} - -func (l *Logger) NoCoordinatorFound() { - l.l.Error("no coordinator found! probably switching state, skipping ...", - zap.String("service", l.service)) -} - -func (l *Logger) CoordinatorChanged(oldHost, newHost string, oldPort, newPort int) { - l.l.Info("coordinator changed, connecting to new coordinator.", - zap.String("service", l.service), - zap.String("old-coordinator", fmt.Sprintf("%s:%d", oldHost, oldPort)), - zap.String("new-coordinator", fmt.Sprintf("%s:%d", newHost, newPort))) -} - -func (l *Logger) CoordinatorConnectionLost(host string, port int) { - l.l.Warn("coordinator connection lost, reconnecting ...", - zap.String("service", l.service), - zap.String("host", host), zap.Int("port", port)) -} - -func (l *Logger) CoordinatorConnectionFailed(host string, port int, err error) { - l.l.Error("connecting to coordinator failed!", - zap.String("service", l.service), - zap.String("host", host), zap.Int("port", port), zap.Error(err)) -} - -func (l *Logger) GetCoordinatorFailed(err error) { - l.l.Error("failed to get coordinator, skipping ...", - zap.String("service", l.service), zap.Error(err)) -} - -func (l *Logger) GetWorkersFailed(err error) { - if err == sql.ErrNoRows { - l.NoWorkersFound() - return - } - l.l.Error("failed to get workers!", - zap.String("service", l.service), zap.Error(err)) -} - -func (l *Logger) WorkerPrimaryCheckFailed(err error, workerID int) { - l.l.Error("failed to check if worker is primary!", - zap.String("service", l.service), zap.Error(err), zap.Int("worker-id", workerID)) -} - -func (l *Logger) WorkerStateChange(oldHost, newHost string, oldPort, newPort int) { - oldWorker := fmt.Sprintf("%s:%d", oldHost, oldPort) - newWorker := fmt.Sprintf("%s:%d", newHost, newPort) - l.l.Info("worker change detected, updating coordinator ...", - zap.String("service", l.service), - zap.String("old-worker", oldWorker), zap.String("new-worker", newWorker)) -} - -func (l *Logger) WorkerUpdated(oldHost, newHost string, oldPort, newPort int) { - oldWorker := fmt.Sprintf("%s:%d", oldHost, oldPort) - newWorker := fmt.Sprintf("%s:%d", newHost, newPort) - l.l.Info("worker updated", - zap.String("service", l.service), - zap.String("old-worker", oldWorker), zap.String("new-worker", newWorker)) -} - -func (l *Logger) WorkerUpdateFailed(err error) { - l.l.Error("failed to update worker in coordinator", - zap.String("service", l.service), zap.Error(err)) -} - -func (l *Logger) NoWorkersFound() { - l.l.Error("no workers found!", - zap.String("service", l.service)) -} diff --git a/main.go b/main.go index 0b494f3..a821f38 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "flag" + "github.com/Navid2zp/citus-failover/api" "github.com/Navid2zp/citus-failover/config" "github.com/Navid2zp/citus-failover/core" ) @@ -13,6 +14,11 @@ func main() { if err != nil { panic(err) } + + if config.Config.API.Enabled { + go api.Serve() + } + core.InitMonitor() core.Monitor() } \ No newline at end of file