diff --git a/plugins/inputs/mysql/mysql.go b/plugins/inputs/mysql/mysql.go index 0dd4febc7..1f9a1b18a 100644 --- a/plugins/inputs/mysql/mysql.go +++ b/plugins/inputs/mysql/mysql.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "reflect" + "regexp" "strconv" "strings" "sync" @@ -26,6 +27,8 @@ import ( //go:embed sample.conf var sampleConfig string +var tlsRe = regexp.MustCompile(`([\?&])(?:tls=custom)($|&)`) + type Mysql struct { Servers []*config.Secret `toml:"servers"` PerfEventsStatementsDigestTextLimit int64 `toml:"perf_events_statements_digest_text_limit"` @@ -52,9 +55,9 @@ type Mysql struct { PerfSummaryEvents []string `toml:"perf_summary_events"` IntervalSlow config.Duration `toml:"interval_slow"` MetricVersion int `toml:"metric_version"` - - Log telegraf.Logger `toml:"-"` + Log telegraf.Logger `toml:"-"` tls.ClientConfig + lastT time.Time getStatusQuery string loggedConvertFields map[string]bool @@ -115,6 +118,12 @@ func (m *Mysql) Init() error { } dsn := dsnSecret.String() 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) if err != nil { return fmt.Errorf("parsing %q failed: %w", dsn, err) @@ -125,14 +134,10 @@ func (m *Mysql) Init() error { 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 { return fmt.Errorf("replacing server %q failed: %w", dsn, err) } + m.Servers[i] = server } diff --git a/plugins/inputs/mysql/mysql_test.go b/plugins/inputs/mysql/mysql_test.go index b71db7347..3dec845a2 100644 --- a/plugins/inputs/mysql/mysql_test.go +++ b/plugins/inputs/mysql/mysql_test.go @@ -2,6 +2,8 @@ package mysql import ( "fmt" + "regexp" + "strings" "testing" "time" @@ -11,6 +13,7 @@ import ( "github.com/testcontainers/testcontainers-go/wait" "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/plugins/common/tls" "github.com/influxdata/telegraf/testutil" ) @@ -295,9 +298,118 @@ func TestMysqlDNSAddTimeout(t *testing.T) { Servers: []*config.Secret{&s}, } 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.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-", + }, + { + 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-", + }, + { + 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-", + }, + { + 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-&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 `` part with a potential actual ID + actual := rs.String() + expected := test.expected + if strings.Contains(expected, "") { + matches := customIDRe.FindStringSubmatch(actual) + if len(matches) == 2 { + expected = strings.Replace(expected, "", matches[1], 1) + } + } + + require.Equal(t, expected, actual) }) } }