mirror of
https://github.com/grafana/grafana.git
synced 2026-02-19 02:30:53 -05:00
* Moving things around
* Copy parseURL function to where it's used
* Update test
* Remove experimental-strip-types
* Revert "Remove experimental-strip-types"
This reverts commit 70fbc1c0cd.
* Trigger build
116 lines
3.4 KiB
Go
116 lines
3.4 KiB
Go
package datasource
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
)
|
|
|
|
var logger = log.New("datasource")
|
|
|
|
// requiredURL contains the set of data sources that require a URL.
|
|
var requiredURL = map[string]bool{
|
|
datasources.DS_GRAPHITE: true,
|
|
datasources.DS_INFLUXDB: true,
|
|
datasources.DS_INFLUXDB_08: true,
|
|
datasources.DS_ES: true,
|
|
datasources.DS_PROMETHEUS: true,
|
|
datasources.DS_AMAZON_PROMETHEUS: true,
|
|
datasources.DS_AZURE_PROMETHEUS: true,
|
|
datasources.DS_ALERTMANAGER: true,
|
|
datasources.DS_JAEGER: true,
|
|
datasources.DS_LOKI: true,
|
|
datasources.DS_OPENTSDB: true,
|
|
datasources.DS_TEMPO: true,
|
|
datasources.DS_ZIPKIN: true,
|
|
datasources.DS_MYSQL: true,
|
|
datasources.DS_POSTGRES: true,
|
|
datasources.DS_MSSQL: true,
|
|
}
|
|
|
|
// URLValidationError represents an error from validating a data source URL.
|
|
type URLValidationError struct {
|
|
Err error
|
|
|
|
URL string
|
|
}
|
|
|
|
// Error returns the error message.
|
|
func (e URLValidationError) Error() string {
|
|
return fmt.Sprintf("validation of data source URL %q failed: %s", e.URL, e.Err.Error())
|
|
}
|
|
|
|
// nolint:unused
|
|
// Unwrap returns the wrapped error.
|
|
// Used by errors package.
|
|
func (e URLValidationError) Unwrap() error {
|
|
return e.Err
|
|
}
|
|
|
|
// reURL is a regexp to detect if a URL specifies the protocol. We match also strings where the actual protocol is
|
|
// missing (i.e., "://"), in order to catch these as invalid when parsing.
|
|
var reURL = regexp.MustCompile("^[^:]*://")
|
|
|
|
// ValidateURL validates a data source's URL.
|
|
//
|
|
// The data source's type and URL must be provided. If successful, the valid URL object is returned, otherwise an
|
|
// error is returned.
|
|
func ValidateURL(typeName, urlStr string) (*url.URL, error) {
|
|
// Check for empty URLs
|
|
if _, exists := requiredURL[typeName]; exists && strings.TrimSpace(urlStr) == "" {
|
|
return nil, URLValidationError{Err: errors.New("empty URL string"), URL: ""}
|
|
}
|
|
|
|
var u *url.URL
|
|
var err error
|
|
switch strings.ToLower(typeName) {
|
|
case "mssql":
|
|
u, err = parseURL(urlStr, logger)
|
|
default:
|
|
logger.Debug("Applying default URL parsing for this data source type", "type", typeName, "url", urlStr)
|
|
|
|
// Make sure the URL starts with a protocol specifier, so parsing is unambiguous
|
|
if !reURL.MatchString(urlStr) {
|
|
logger.Debug(
|
|
"Data source URL doesn't specify protocol, so prepending it with http:// in order to make it unambiguous",
|
|
"type", typeName, "url", urlStr)
|
|
urlStr = fmt.Sprintf("http://%s", urlStr)
|
|
}
|
|
u, err = url.Parse(urlStr)
|
|
}
|
|
if err != nil {
|
|
return nil, URLValidationError{Err: err, URL: urlStr}
|
|
}
|
|
|
|
return u, nil
|
|
}
|
|
|
|
type DebugOnlyLogger interface {
|
|
Debug(msg string, args ...interface{})
|
|
}
|
|
|
|
// ParseURL tries to parse an URL string into a URL object.
|
|
func parseURL(u string, logger DebugOnlyLogger) (*url.URL, error) {
|
|
logger.Debug("Parsing 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 URL format: %q", u)
|
|
}
|
|
return &url.URL{
|
|
Scheme: "sqlserver",
|
|
Host: host,
|
|
}, nil
|
|
}
|