diff --git a/go.mod b/go.mod index 20f6c72e0..af675ac59 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/aliyun/aliyun-oss-go-sdk v2.2.8+incompatible github.com/go-redis/redis v6.15.9+incompatible github.com/go-sql-driver/mysql v1.7.1 + github.com/go-zookeeper/zk v1.0.3 github.com/redis/go-redis/v9 v9.0.5 github.com/tencentyun/cos-go-sdk-v5 v0.7.42 ) @@ -68,7 +69,6 @@ require ( github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-zookeeper/zk v1.0.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.5.9 // indirect diff --git a/go.work b/go.work index 09e86f032..757933536 100644 --- a/go.work +++ b/go.work @@ -1,7 +1,8 @@ go 1.20 use ( - . + . + ./tools/component ./tools/infra ./tools/ncpu ) diff --git a/tools/component/check_component.go b/tools/component/check_component.go new file mode 100644 index 000000000..93461f640 --- /dev/null +++ b/tools/component/check_component.go @@ -0,0 +1,160 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "github.com/OpenIMSDK/Open-IM-Server/pkg/common/config" + "github.com/OpenIMSDK/tools/utils" + "github.com/Shopify/sarama" + "github.com/go-zookeeper/zk" + "github.com/minio/minio-go/v7" + "github.com/redis/go-redis/v9" + "go.mongodb.org/mongo-driver/mongo/readpref" + "net" + "net/url" + "strings" + "time" + + "github.com/minio/minio-go/v7/pkg/credentials" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +const ( + sqlDriver = "mysql" + minioHealthCheckDuration = 1 + maxRetry = 3 +) + +func main() { + + for i := 0; i < maxRetry; i++ { + success := 1 + // Check MySQL + db, err := sql.Open(sqlDriver, fmt.Sprintf("%s:%s@tcp(%s)/", + config.Config.Mysql.Username, config.Config.Mysql.Password, config.Config.Mysql.Address)) + if err != nil { + fmt.Printf("Cannot connect to MySQL: %v", err) + success = 0 + } + err = db.Ping() + if err != nil { + fmt.Printf("ping mysql failed: %v. please make sure your mysql service has started", err) + success = 0 + } + db.Close() + + // Check MongoDB + client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI( + fmt.Sprintf("mongodb://%s:%s@%s", + config.Config.Mongo.Username, config.Config.Mongo.Password, config.Config.Mongo.Address))) + if err != nil { + fmt.Printf("Cannot connect to MongoDB: %v", err) + success = 0 + } + err = client.Ping(context.TODO(), &readpref.ReadPref{}) + if err != nil { + fmt.Printf("ping mysql failed: %v. please make sure your mysql service has started", err) + success = 0 + } + client.Disconnect(context.TODO()) + + // Check Minio + if config.Config.Object.Enable == "minio" { + if exactIP(config.Config.Object.ApiURL) == "127.0.0.1" && config.Config.Object.ApiURL == config.Config.Object.Minio.Endpoint { + fmt.Printf("ApiURL contain the same address with Endpoint: %v. please modify the config file", config.Config.Object.ApiURL) + } + minioClient, err := minio.New(config.Config.Object.Minio.Endpoint, &minio.Options{ + Creds: credentials.NewStaticV4(config.Config.Object.Minio.AccessKeyID, config.Config.Object.Minio.SecretAccessKey, ""), + Secure: false, + }) + if err != nil { + fmt.Printf("Cannot connect to Minio: %v", err) + success = 0 + } + cancel, err := minioClient.HealthCheck(time.Duration(minioHealthCheckDuration)) + if err != nil { + fmt.Printf("starting minio health check failed:%v", err) + success = 0 + } + if minioClient.IsOffline() { + fmt.Printf("Error: minio server is offline.") + success = 0 + } + cancel() + } + + // Check Redis + var redisClient redis.UniversalClient + if len(config.Config.Redis.Address) > 1 { + redisClient = redis.NewClusterClient(&redis.ClusterOptions{ + Addrs: config.Config.Redis.Address, + Username: config.Config.Redis.Username, + Password: config.Config.Redis.Password, + }) + } else { + redisClient = redis.NewClient(&redis.Options{ + Addr: config.Config.Redis.Address[0], + Username: config.Config.Redis.Username, + Password: config.Config.Redis.Password, + }) + } + _, err = redisClient.Ping(context.Background()).Result() + if err != nil { + fmt.Printf("Cannot connect to Redis: %v", err) + success = 0 + } + + // Check Zookeeper + c, _, err := zk.Connect(config.Config.Zookeeper.ZkAddr, time.Second) + if err != nil { + fmt.Printf("Cannot connect to Zookeeper: %v", err) + success = 0 + } + c.Close() + + // Check Kafka + kafkaClient, err := sarama.NewClient(config.Config.Kafka.Addr, &sarama.Config{}) + if err != nil { + fmt.Printf("Cannot connect to Kafka: %v", err) + success = 0 + } else { + topics, err := kafkaClient.Topics() + if err != nil { + fmt.Println("get kafka topic error") + success = 0 + } + if !utils.IsContain(config.Config.Kafka.MsgToMongo.Topic, topics) { + fmt.Printf("kafka doesn't contain topic:%v", config.Config.Kafka.MsgToMongo.Topic) + success = 0 + } + if !utils.IsContain(config.Config.Kafka.MsgToPush.Topic, topics) { + fmt.Printf("kafka doesn't contain topic:%v", config.Config.Kafka.MsgToPush.Topic) + success = 0 + } + if !utils.IsContain(config.Config.Kafka.LatestMsgToRedis.Topic, topics) { + fmt.Printf("kafka doesn't contain topic:%v", config.Config.Kafka.LatestMsgToRedis.Topic) + success = 0 + } + } + kafkaClient.Close() + if success == 1 { + fmt.Println("all compose check pass") + return + } + time.Sleep(3 * time.Second) + } +} + +func exactIP(urll string) string { + u, _ := url.Parse(urll) + host, _, err := net.SplitHostPort(u.Host) + if err != nil { + host = u.Host + } + if strings.HasSuffix(host, ":") { + host = host[0 : len(host)-1] + } + return host +} diff --git a/tools/component/go.mod b/tools/component/go.mod new file mode 100644 index 000000000..bc7abc133 --- /dev/null +++ b/tools/component/go.mod @@ -0,0 +1,3 @@ +module github.com/OpenIMSDK/Open-IM-Server/tools/component + +go 1.19