From 8f69d8ba73a0ba0439fd26d423d42e21a4af7384 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Fri, 7 Mar 2025 03:16:30 +0300 Subject: [PATCH] PMM-12153 reconfigure MySQL agent --- managed/services/agents/mysql.go | 82 ++++++++++++++------------- managed/services/agents/mysql_test.go | 30 ++++++---- managed/services/agents/state.go | 6 +- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/managed/services/agents/mysql.go b/managed/services/agents/mysql.go index cef276fa87..7c66e2275e 100644 --- a/managed/services/agents/mysql.go +++ b/managed/services/agents/mysql.go @@ -27,18 +27,20 @@ import ( "github.com/percona/pmm/version" ) -var mysqlExporterVersionWithPluginCollector = version.MustParse("2.36.0-0") -var mysqlExporterVersion30 = version.MustParse("3.0.0-0") - -// The mysqldExporterConfig returns desired configuration of mysqld_exporter process. +var ( + mysqlExporterVersionWithPluginCollector = version.MustParse("2.36.0-0") + // TODO: put back to 3.2.0 before release + v3_2_0 = version.MustParse("3.1.0-0") +) +// mysqldExporterConfig returns desired configuration of mysqld_exporter process. func mysqldExporterConfig( node *models.Node, service *models.Service, exporter *models.Agent, redactMode redactMode, pmmAgentVersion *version.Parsed, -) *agentv1.SetStateRequest_AgentProcess { +) (*agentv1.SetStateRequest_AgentProcess, error) { listenAddress := getExporterListenAddress(node, exporter) tdp := exporter.TemplateDelimiters(service) @@ -85,7 +87,7 @@ func mysqldExporterConfig( args = append(args, "--collect.plugins") } - if pmmAgentVersion.Less(mysqlExporterVersion30) { + if pmmAgentVersion.Less(v3_2_0) { args = append(args, "--exporter.global-conn-pool") } @@ -115,35 +117,25 @@ func mysqldExporterConfig( files := exporter.Files() if files != nil { + // // Newer versions of exporter expect these to be provided in `my.cnf` file + // if pmmAgentVersion.Less(v3_2_0) { for k := range files { - if pmmAgentVersion.Less(mysqlExporterVersion30) { - switch k { - case "tlsCa": - args = append(args, "--mysql.ssl-ca-file="+tdp.Left+" .TextFiles.tlsCa "+tdp.Right) - case "tlsCert": - args = append(args, "--mysql.ssl-cert-file="+tdp.Left+" .TextFiles.tlsCert "+tdp.Right) - case "tlsKey": - args = append(args, "--mysql.ssl-key-file="+tdp.Left+" .TextFiles.tlsKey "+tdp.Right) - default: - continue - } - } else { - switch k { - case "tlsCa": - args = append(args, "--tls.ca="+tdp.Left+" .TextFiles.tlsCa "+tdp.Right) - case "tlsCert": - args = append(args, "--tls.cert="+tdp.Left+" .TextFiles.tlsCert "+tdp.Right) - case "tlsKey": - args = append(args, "--tls.key="+tdp.Left+" .TextFiles.tlsKey "+tdp.Right) - default: - continue - } + switch k { + case "tlsCa": + args = append(args, "--mysql.ssl-ca-file="+tdp.Left+" .TextFiles.tlsCa "+tdp.Right) + case "tlsCert": + args = append(args, "--mysql.ssl-cert-file="+tdp.Left+" .TextFiles.tlsCert "+tdp.Right) + case "tlsKey": + args = append(args, "--mysql.ssl-key-file="+tdp.Left+" .TextFiles.tlsKey "+tdp.Right) + default: + continue } } + // } if exporter.TLSSkipVerify { - if pmmAgentVersion.Less(mysqlExporterVersion30) { - args = append(args, "--mysql.ssl-insecure-skip-verify") + if pmmAgentVersion.Less(v3_2_0) { + args = append(args, "--mysql.ssl-skip-verify") } else { args = append(args, "--tls.insecure-skip-verify") } @@ -154,24 +146,36 @@ func mysqldExporterConfig( sort.Strings(args) - var env []string - if pmmAgentVersion.Less(mysqlExporterVersion30) { - env = []string{ - fmt.Sprintf("DATA_SOURCE_NAME=%s", exporter.DSN(service, models.DSNParams{DialTimeout: time.Second, Database: ""}, nil, pmmAgentVersion)), - fmt.Sprintf("HTTP_AUTH=pmm:%s", exporter.GetAgentPassword()), - } - } res := &agentv1.SetStateRequest_AgentProcess{ Type: inventoryv1.AgentType_AGENT_TYPE_MYSQLD_EXPORTER, TemplateLeftDelim: tdp.Left, TemplateRightDelim: tdp.Right, Args: args, - Env: env, + TextFiles: files, } + if pmmAgentVersion.Less(v3_2_0) { + env := []string{ + fmt.Sprintf("DATA_SOURCE_NAME=%s", exporter.DSN(service, models.DSNParams{DialTimeout: time.Second, Database: ""}, nil, pmmAgentVersion)), + fmt.Sprintf("HTTP_AUTH=pmm:%s", exporter.GetAgentPassword()), + } + res.Env = env + } else { + cfg, err := exporter.BuildMyCnfConfig(service) + if err != nil { + return nil, err + } + res.TextFiles["myCnf"] = cfg + res.Args = append(res.Args, "--config.my-cnf="+tdp.Left+" .TextFiles.myCnf "+tdp.Right) + + if err := ensureAuthParams(exporter, res, pmmAgentVersion, v3_2_0, true); err != nil { + return nil, err + } + } + if redactMode != exposeSecrets { res.RedactWords = redactWords(exporter) } - return res + return res, nil } // qanMySQLPerfSchemaAgentConfig returns desired configuration of qan-mysql-perfschema built-in agent. diff --git a/managed/services/agents/mysql_test.go b/managed/services/agents/mysql_test.go index d3ed5a3a7b..3e64c51b0b 100644 --- a/managed/services/agents/mysql_test.go +++ b/managed/services/agents/mysql_test.go @@ -47,7 +47,7 @@ func TestMySQLdExporterConfig(t *testing.T) { } pmmAgentVersion := version.MustParse("2.21.0") - actual := mysqldExporterConfig(node, mysql, exporter, redactSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, redactSecrets, pmmAgentVersion) expected := &agentv1.SetStateRequest_AgentProcess{ Type: inventoryv1.AgentType_AGENT_TYPE_MYSQLD_EXPORTER, TemplateLeftDelim: "{{", @@ -99,19 +99,22 @@ func TestMySQLdExporterConfig(t *testing.T) { RedactWords: []string{"s3cur3 p@$$w0r4.", "agent-password"}, } requireNoDuplicateFlags(t, actual.Args) + require.NoError(t, err) require.Equal(t, expected.Args, actual.Args) require.Equal(t, expected.Env, actual.Env) require.Equal(t, expected, actual) t.Run("EmptyPassword", func(t *testing.T) { exporter.Password = nil - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + require.NoError(t, err) assert.Equal(t, "DATA_SOURCE_NAME=username@tcp(1.2.3.4:3306)/?timeout=1s", actual.Env[0]) }) t.Run("EmptyUsername", func(t *testing.T) { exporter.Username = nil - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + require.NoError(t, err) assert.Equal(t, "DATA_SOURCE_NAME=tcp(1.2.3.4:3306)/?timeout=1s", actual.Env[0]) }) @@ -122,7 +125,7 @@ func TestMySQLdExporterConfig(t *testing.T) { TLSCert: "content-of-tls-certificate-key", TLSKey: "content-of-tls-key", } - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) expected := "DATA_SOURCE_NAME=tcp(1.2.3.4:3306)/?timeout=1s&tls=custom" assert.Equal(t, expected, actual.Env[0]) expectedFiles := map[string]string{ @@ -130,6 +133,7 @@ func TestMySQLdExporterConfig(t *testing.T) { "tlsCert": exporter.MySQLOptions.TLSCert, "tlsKey": exporter.MySQLOptions.TLSKey, } + require.NoError(t, err) assert.Equal(t, expectedFiles, actual.TextFiles) }) } @@ -158,7 +162,7 @@ func TestMySQLdExporterConfigTablestatsGroupDisabled(t *testing.T) { } pmmAgentVersion := version.MustParse("2.24.0") - actual := mysqldExporterConfig(node, mysql, exporter, redactSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, redactSecrets, pmmAgentVersion) expected := &agentv1.SetStateRequest_AgentProcess{ Type: inventoryv1.AgentType_AGENT_TYPE_MYSQLD_EXPORTER, TemplateLeftDelim: "{{", @@ -210,31 +214,36 @@ func TestMySQLdExporterConfigTablestatsGroupDisabled(t *testing.T) { }, } requireNoDuplicateFlags(t, actual.Args) + require.NoError(t, err) require.Equal(t, expected.Args, actual.Args) require.Equal(t, expected.Env, actual.Env) require.Equal(t, expected, actual) t.Run("EmptyPassword", func(t *testing.T) { exporter.Password = nil - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + require.NoError(t, err) assert.Equal(t, "DATA_SOURCE_NAME=username@tcp(1.2.3.4:3306)/?timeout=1s&tls=custom", actual.Env[0]) }) t.Run("EmptyUsername", func(t *testing.T) { exporter.Username = nil - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + require.NoError(t, err) assert.Equal(t, "DATA_SOURCE_NAME=tcp(1.2.3.4:3306)/?timeout=1s&tls=custom", actual.Env[0]) }) t.Run("V236_EnablesPluginCollector", func(t *testing.T) { pmmAgentVersion := version.MustParse("2.36.0") - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + require.NoError(t, err) assert.Contains(t, actual.Args, "--collect.plugins") }) t.Run("beforeV236_NoPluginCollector", func(t *testing.T) { pmmAgentVersion := version.MustParse("2.35.0") - actual := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, exposeSecrets, pmmAgentVersion) + require.NoError(t, err) assert.NotContains(t, actual.Args, "--collect.plugins") }) } @@ -259,7 +268,7 @@ func TestMySQLdExporterConfigDisabledCollectors(t *testing.T) { } pmmAgentVersion := version.MustParse("2.24.0") - actual := mysqldExporterConfig(node, mysql, exporter, redactSecrets, pmmAgentVersion) + actual, err := mysqldExporterConfig(node, mysql, exporter, redactSecrets, pmmAgentVersion) expected := &agentv1.SetStateRequest_AgentProcess{ Type: inventoryv1.AgentType_AGENT_TYPE_MYSQLD_EXPORTER, TemplateLeftDelim: "{{", @@ -307,6 +316,7 @@ func TestMySQLdExporterConfigDisabledCollectors(t *testing.T) { RedactWords: []string{"s3cur3 p@$$w0r4."}, } requireNoDuplicateFlags(t, actual.Args) + require.NoError(t, err) require.Equal(t, expected.Args, actual.Args) require.Equal(t, expected.Env, actual.Env) require.Equal(t, expected, actual) diff --git a/managed/services/agents/state.go b/managed/services/agents/state.go index c10c71b567..c4a2ebf1a7 100644 --- a/managed/services/agents/state.go +++ b/managed/services/agents/state.go @@ -229,7 +229,11 @@ func (u *StateUpdater) sendSetStateRequest(ctx context.Context, agent *pmmAgentI node, _ := models.FindNodeByID(u.db.Querier, pointer.GetString(pmmAgent.RunsOnNodeID)) switch row.AgentType { //nolint:exhaustive case models.MySQLdExporterType: - agentProcesses[row.AgentID] = mysqldExporterConfig(node, service, row, redactMode, pmmAgentVersion) + cfg, err := mysqldExporterConfig(node, service, row, redactMode, pmmAgentVersion) + if err != nil { + return err + } + agentProcesses[row.AgentID] = cfg case models.MongoDBExporterType: cfg, err := mongodbExporterConfig(node, service, row, redactMode, pmmAgentVersion) if err != nil {