Files
1Panel/agent/app/service/mongodb_client.go
2026-05-22 15:17:59 +08:00

148 lines
3.6 KiB
Go

package service
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"net/url"
"strconv"
"time"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/mongo/readpref"
)
type mongodbConnectionInfo struct {
Address string
Port uint
InitialDB string
Username string
Password string
Timeout uint
SSL bool
RootCert string
ClientKey string
ClientCert string
SkipVerify bool
}
func mongodbConnectionInfoFromCreate(req dto.DatabaseCreate) mongodbConnectionInfo {
return mongodbConnectionInfo{
Address: req.Address,
Port: req.Port,
InitialDB: req.InitialDB,
Username: req.Username,
Password: req.Password,
Timeout: req.Timeout,
SSL: req.SSL,
RootCert: req.RootCert,
ClientKey: req.ClientKey,
ClientCert: req.ClientCert,
SkipVerify: req.SkipVerify,
}
}
func mongodbConnectionInfoFromModel(db model.Database) mongodbConnectionInfo {
return mongodbConnectionInfo{
Address: db.Address,
Port: db.Port,
InitialDB: db.InitialDB,
Username: db.Username,
Password: db.Password,
Timeout: db.Timeout,
SSL: db.SSL,
RootCert: db.RootCert,
ClientKey: db.ClientKey,
ClientCert: db.ClientCert,
SkipVerify: db.SkipVerify,
}
}
func loadRemoteMongodbConnection(database string) (mongodbConnectionInfo, error) {
db, err := databaseRepo.Get(repo.WithByName(database))
if err != nil {
return mongodbConnectionInfo{}, err
}
return mongodbConnectionInfoFromModel(db), nil
}
func newRemoteMongodbClient(info mongodbConnectionInfo) (*mongo.Client, context.Context, context.CancelFunc, error) {
timeout := time.Duration(info.Timeout) * time.Second
if timeout == 0 {
timeout = 30 * time.Second
}
clientOptions := options.Client().ApplyURI(buildRemoteMongodbURI(info)).
SetServerSelectionTimeout(timeout).
SetConnectTimeout(timeout)
if info.SSL {
tlsConfig, err := buildRemoteMongodbTLSConfig(info)
if err != nil {
return nil, nil, nil, err
}
clientOptions.SetTLSConfig(tlsConfig)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
client, err := mongo.Connect(clientOptions)
if err != nil {
cancel()
return nil, nil, nil, err
}
if err := client.Ping(ctx, readpref.Primary()); err != nil {
_ = client.Disconnect(context.Background())
cancel()
return nil, nil, nil, err
}
return client, ctx, cancel, nil
}
func buildRemoteMongodbURI(info mongodbConnectionInfo) string {
uri := url.URL{
Scheme: "mongodb",
Host: net.JoinHostPort(info.Address, strconv.Itoa(int(info.Port))),
Path: "/",
}
uri.User = url.UserPassword(info.Username, info.Password)
query := url.Values{}
authSource := info.InitialDB
if authSource == "" {
authSource = "admin"
}
query.Set("authSource", authSource)
query.Set("directConnection", "true")
uri.RawQuery = query.Encode()
return uri.String()
}
func buildRemoteMongodbTLSConfig(info mongodbConnectionInfo) (*tls.Config, error) {
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: info.SkipVerify,
}
if info.RootCert != "" {
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM([]byte(info.RootCert)) {
return nil, fmt.Errorf("load mongodb ca cert failed")
}
tlsConfig.RootCAs = pool
}
if info.ClientCert != "" && info.ClientKey != "" {
cert, err := tls.X509KeyPair([]byte(info.ClientCert), []byte(info.ClientKey))
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
return tlsConfig, nil
}