fix(inputs.mysql): Handle custom TLS configs correctly (#15493)
This commit is contained in:
parent
d8fb6e4c98
commit
53ae9841d0
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -26,6 +27,8 @@ import (
|
||||||
//go:embed sample.conf
|
//go:embed sample.conf
|
||||||
var sampleConfig string
|
var sampleConfig string
|
||||||
|
|
||||||
|
var tlsRe = regexp.MustCompile(`([\?&])(?:tls=custom)($|&)`)
|
||||||
|
|
||||||
type Mysql struct {
|
type Mysql struct {
|
||||||
Servers []*config.Secret `toml:"servers"`
|
Servers []*config.Secret `toml:"servers"`
|
||||||
PerfEventsStatementsDigestTextLimit int64 `toml:"perf_events_statements_digest_text_limit"`
|
PerfEventsStatementsDigestTextLimit int64 `toml:"perf_events_statements_digest_text_limit"`
|
||||||
|
|
@ -52,9 +55,9 @@ type Mysql struct {
|
||||||
PerfSummaryEvents []string `toml:"perf_summary_events"`
|
PerfSummaryEvents []string `toml:"perf_summary_events"`
|
||||||
IntervalSlow config.Duration `toml:"interval_slow"`
|
IntervalSlow config.Duration `toml:"interval_slow"`
|
||||||
MetricVersion int `toml:"metric_version"`
|
MetricVersion int `toml:"metric_version"`
|
||||||
|
Log telegraf.Logger `toml:"-"`
|
||||||
Log telegraf.Logger `toml:"-"`
|
|
||||||
tls.ClientConfig
|
tls.ClientConfig
|
||||||
|
|
||||||
lastT time.Time
|
lastT time.Time
|
||||||
getStatusQuery string
|
getStatusQuery string
|
||||||
loggedConvertFields map[string]bool
|
loggedConvertFields map[string]bool
|
||||||
|
|
@ -115,6 +118,12 @@ func (m *Mysql) Init() error {
|
||||||
}
|
}
|
||||||
dsn := dsnSecret.String()
|
dsn := dsnSecret.String()
|
||||||
dsnSecret.Destroy()
|
dsnSecret.Destroy()
|
||||||
|
|
||||||
|
// Reference the custom TLS config of _THIS_ plugin instance
|
||||||
|
if tlsRe.MatchString(dsn) {
|
||||||
|
dsn = tlsRe.ReplaceAllString(dsn, "${1}tls="+tlsid+"${2}")
|
||||||
|
}
|
||||||
|
|
||||||
conf, err := mysql.ParseDSN(dsn)
|
conf, err := mysql.ParseDSN(dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parsing %q failed: %w", dsn, err)
|
return fmt.Errorf("parsing %q failed: %w", dsn, err)
|
||||||
|
|
@ -125,14 +134,10 @@ func (m *Mysql) Init() error {
|
||||||
conf.Timeout = time.Second * 5
|
conf.Timeout = time.Second * 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference the custom TLS config of _THIS_ plugin instance
|
|
||||||
if conf.TLSConfig == "custom" {
|
|
||||||
conf.TLSConfig = tlsid
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := server.Set([]byte(conf.FormatDSN())); err != nil {
|
if err := server.Set([]byte(conf.FormatDSN())); err != nil {
|
||||||
return fmt.Errorf("replacing server %q failed: %w", dsn, err)
|
return fmt.Errorf("replacing server %q failed: %w", dsn, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Servers[i] = server
|
m.Servers[i] = server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package mysql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -11,6 +13,7 @@ import (
|
||||||
"github.com/testcontainers/testcontainers-go/wait"
|
"github.com/testcontainers/testcontainers-go/wait"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/config"
|
"github.com/influxdata/telegraf/config"
|
||||||
|
"github.com/influxdata/telegraf/plugins/common/tls"
|
||||||
"github.com/influxdata/telegraf/testutil"
|
"github.com/influxdata/telegraf/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -295,9 +298,118 @@ func TestMysqlDNSAddTimeout(t *testing.T) {
|
||||||
Servers: []*config.Secret{&s},
|
Servers: []*config.Secret{&s},
|
||||||
}
|
}
|
||||||
require.NoError(t, m.Init())
|
require.NoError(t, m.Init())
|
||||||
equal, err := m.Servers[0].EqualTo([]byte(tt.output))
|
require.Len(t, m.Servers, 1)
|
||||||
|
dsn, err := m.Servers[0].Get()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, equal)
|
defer dsn.Destroy()
|
||||||
|
require.Equal(t, tt.output, dsn.TemporaryString())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMysqlTLSCustomization(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
errmsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "custom only param",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=custom",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=custom-<id>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom start param",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=custom&timeout=20s",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom-<id>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom end param",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom-<id>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom middle param",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom&foo=bar",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s&tls=custom-<id>&foo=bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param false",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=false",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param true",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=true",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=true",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param skip-verify",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=skip-verify",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=5s&tls=skip-verify",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param preferred",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=preferred",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?allowFallbackToPlaintext=true&timeout=5s&tls=preferred",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param customcfg",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=customcfg",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?tls=customcfg",
|
||||||
|
errmsg: "invalid value / unknown config name: customcfg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param custom-cfg",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg",
|
||||||
|
errmsg: "invalid value / unknown config name: custom-cfg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param custom-cfg and following",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg&timeout=20s",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?tls=custom-cfg&timeout=20s",
|
||||||
|
errmsg: "invalid value / unknown config name: custom-cfg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-custom param notls keyword",
|
||||||
|
input: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s¬ls=custom",
|
||||||
|
expected: "root:passwd@tcp(192.168.1.1:3306)/?timeout=20s¬ls=custom",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
customIDRe := regexp.MustCompile(`[\?&]tls=custom-([\w-]*)(?:$|&)`)
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
s := config.NewSecret([]byte(test.input))
|
||||||
|
plugin := &Mysql{
|
||||||
|
Servers: []*config.Secret{&s},
|
||||||
|
ClientConfig: tls.ClientConfig{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
err := plugin.Init()
|
||||||
|
if test.errmsg != "" {
|
||||||
|
require.ErrorContains(t, err, test.errmsg)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Len(t, plugin.Servers, 1)
|
||||||
|
rs, err := plugin.Servers[0].Get()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer rs.Destroy()
|
||||||
|
|
||||||
|
// Replace the `<id>` part with a potential actual ID
|
||||||
|
actual := rs.String()
|
||||||
|
expected := test.expected
|
||||||
|
if strings.Contains(expected, "<id>") {
|
||||||
|
matches := customIDRe.FindStringSubmatch(actual)
|
||||||
|
if len(matches) == 2 {
|
||||||
|
expected = strings.Replace(expected, "<id>", matches[1], 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue