API: Recognize MSSQL data source URLs (#25629)

* API: Recognize MSSQL URLs

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Move MSSQL URL validation into mssql package

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
Arve Knudsen
2020-06-17 11:17:11 +02:00
committed by GitHub
parent e6a5e88054
commit d352c213b3
5 changed files with 133 additions and 26 deletions

View File

@@ -3,17 +3,18 @@ package mssql
import (
"database/sql"
"fmt"
"net/url"
"regexp"
"strconv"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
_ "github.com/denisenkom/go-mssqldb"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/tsdb/sqleng"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/errutil"
"xorm.io/core"
)
@@ -21,9 +22,9 @@ func init() {
tsdb.RegisterTsdbQueryEndpoint("mssql", newMssqlQueryEndpoint)
}
func newMssqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
logger := log.New("tsdb.mssql")
var logger = log.New("tsdb.mssql")
func newMssqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
cnnstr, err := generateConnectionString(datasource)
if err != nil {
return nil, err
@@ -46,12 +47,46 @@ func newMssqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin
return sqleng.NewSqlQueryEndpoint(&config, &queryResultTransformer, newMssqlMacroEngine(), logger)
}
// ParseURL tries to parse an MSSQL URL string into a URL object.
func ParseURL(u string) (*url.URL, error) {
logger.Debug("Parsing MSSQL URL", "url", u)
// Recognize ODBC connection strings like host\instance:1234
reODBC := regexp.MustCompile(`^[^\\:]+(?:\\[^:]+)?(?::\d+)?$`)
var host string
switch {
case reODBC.MatchString(u):
logger.Debug("Recognized as ODBC URL format", "url", u)
host = u
default:
logger.Debug("Couldn't recognize as valid MSSQL URL", "url", u)
return nil, fmt.Errorf("unrecognized MSSQL URL format: %q", u)
}
return &url.URL{
Scheme: "sqlserver",
Host: host,
}, nil
}
func generateConnectionString(datasource *models.DataSource) (string, error) {
addr, err := util.SplitHostPortDefault(datasource.Url, "localhost", "1433")
if err != nil {
return "", errutil.Wrapf(err, "Invalid data source URL '%s'", datasource.Url)
var addr util.NetworkAddress
if datasource.Url != "" {
u, err := ParseURL(datasource.Url)
if err != nil {
return "", err
}
addr, err = util.SplitHostPortDefault(u.Host, "localhost", "1433")
if err != nil {
return "", err
}
} else {
addr = util.NetworkAddress{
Host: "localhost",
Port: "1433",
}
}
logger.Debug("Generating connection string", "url", datasource.Url, "host", addr.Host, "port", addr.Port)
encrypt := datasource.JsonData.Get("encrypt").MustString("false")
connStr := fmt.Sprintf("server=%s;port=%s;database=%s;user id=%s;password=%s;",
addr.Host,