Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MM-54986: Disable app and/or agent profiling #658

Merged
merged 7 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/deployer.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,9 @@
"Query": "histogram_quantile(0.99, sum(rate(mattermost_api_time_bucket[1m])) by (le))"
}
]
},
"PyroscopeSettings": {
"EnableAppProfiling": true,
"EnableAgentProfiling": true
}
}
25 changes: 25 additions & 0 deletions deployment/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,31 @@ type Config struct {
// to use. If present, it is used to automatically upload it to the agents and override the agent's config's
// own UsersFilePath.
UsersFilePath string `default:""`
// PyroscopeSettings contains the settings for configuring the continuous profiling through Pyroscope
PyroscopeSettings PyroscopeSettings
}

// PyroscopeSettings contains flags to enable/disable the profiling
// of the different parts of the deployment.
type PyroscopeSettings struct {
// Enable profiling of all the app instances
EnableAppProfiling bool `default:"true"`
// Enable profiling of all the agent instances
EnableAgentProfiling bool `default:"true"`
}

func (ps PyroscopeSettings) GenString(template string, mmTargets, ltTargets []string) string {
pyroscopeAppConfig := ""
if ps.EnableAppProfiling {
pyroscopeAppConfig = strings.Join(mmTargets, ",")
}
pyroscopeAgentsConfig := ""
if ps.EnableAgentProfiling {
pyroscopeAgentsConfig = strings.Join(ltTargets, ",")
}
pyroscopeConfigFile := fmt.Sprintf(template, pyroscopeAppConfig, pyroscopeAgentsConfig)

return pyroscopeConfigFile
}

// TerraformDBSettings contains the necessary data
Expand Down
7 changes: 3 additions & 4 deletions deployment/terraform/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,10 @@ func (t *Terraform) setupMetrics(extAgent *ssh.ExtAgent) error {
if out, err := sshc.Upload(rdr, "/etc/prometheus/prometheus.yml", true); err != nil {
return fmt.Errorf("error upload prometheus config: output: %s, error: %w", out, err)
}

mlog.Info("Updating Pyroscope config", mlog.String("host", t.output.MetricsServer.PublicIP))
pyroscopeConfigFile := fmt.Sprintf(pyroscopeConfig,
strings.Join(mmTargets, ","),
strings.Join(ltTargets, ","),
)
pyroscopeConfigFile := t.config.PyroscopeSettings.GenString(pyroscopeConfig, mmTargets, ltTargets)

rdr = strings.NewReader(pyroscopeConfigFile)
if out, err := sshc.Upload(rdr, "/etc/pyroscope/server.yml", true); err != nil {
return fmt.Errorf("error upload pyroscope config: output: %s, error: %w", out, err)
Expand Down
101 changes: 101 additions & 0 deletions deployment/terraform/strings_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package terraform

import (
"fmt"
"regexp"
"strings"
"testing"

"github.com/mattermost/mattermost-load-test-ng/deployment"
"github.com/stretchr/testify/require"
)

var reListElems = regexp.MustCompile(`\[(.*)\]`)

func TestPyroscopeSettingsGenString(t *testing.T) {
mmTarget := "app-0:8067"
ltTarget := "agent-0:4000"

// The Name represents the state of each setting, with
// 1 meaning true for bool and non-empty for []string,
// and 0 meaning false for bool and empty for []string
testCases := []struct {
Name string
EnableAppProfiling bool
EnableAgentProfiling bool
MMTargets []string
LTTargets []string
}{
{"0000", false, false, []string{}, []string{}},
{"0001", false, false, []string{}, []string{ltTarget}},
{"0010", false, false, []string{mmTarget}, []string{}},
{"0011", false, false, []string{mmTarget}, []string{ltTarget}},
{"0100", false, true, []string{}, []string{}},
{"0101", false, true, []string{}, []string{ltTarget}},
{"0110", false, true, []string{mmTarget}, []string{}},
{"0111", false, true, []string{mmTarget}, []string{ltTarget}},
{"1000", true, false, []string{}, []string{}},
{"1001", true, false, []string{}, []string{ltTarget}},
{"1010", true, false, []string{mmTarget}, []string{}},
{"1011", true, false, []string{mmTarget}, []string{ltTarget}},
{"1100", true, true, []string{}, []string{}},
{"1101", true, true, []string{}, []string{ltTarget}},
{"1110", true, true, []string{mmTarget}, []string{}},
{"1111", true, true, []string{mmTarget}, []string{ltTarget}},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
settings := deployment.PyroscopeSettings{
EnableAppProfiling: tc.EnableAppProfiling,
EnableAgentProfiling: tc.EnableAgentProfiling,
}

generatedYaml := settings.GenString(pyroscopeConfig, tc.MMTargets, tc.LTTargets)

// We need to do some parsing here to get the part we're interested in, which is the targets
// for the app nodes (the first 'targets: [...]' line), and the targets for the agent nodes,
// (the second 'targets: [...]' line), and then we extract everything that is inside the
// square brackets
targets := []string{}
for _, line := range strings.Split(generatedYaml, "\n") {
if strings.Contains(line, "targets") {
matches := reListElems.FindStringSubmatch(line)
fmt.Println(matches)
require.Len(t, matches, 2)
targets = append(targets, matches[1])
}
}
require.Len(t, targets, 2)

// Now we need to reconstruct the slice of targets for the app nodes
actualMMTargets := []string{}
mmTargets := targets[0]
if mmTargets != "" {
actualMMTargets = strings.Split(mmTargets, ",")
}

// And the same for the agent nodes
actualLTTargets := []string{}
ltTargets := targets[1]
if ltTargets != "" {
actualLTTargets = strings.Split(ltTargets, ",")
}

// Now it's time to check the targets for the app nodes
if tc.EnableAppProfiling {
require.ElementsMatch(t, tc.MMTargets, actualMMTargets)
} else {
require.Empty(t, actualMMTargets)
}

// And again for the agent nodes
if tc.EnableAgentProfiling {
require.ElementsMatch(t, tc.LTTargets, actualLTTargets)
} else {
require.Empty(t, actualLTTargets)
}
})
}

}
20 changes: 20 additions & 0 deletions docs/config/deployer.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,23 @@ The name of a host that will be used for two purposes:
- It will override the server's site URL.
- It will populate a new entry in the /etc/hosts file of the app nodes, so that it points to the proxy private IP or, if there's no proxy, to the current app node.
This config is used for tests that require an existing database dump that contains permalinks. These permalinks point to a specific hostname. Without this setting, that hostname is not known by the nodes of a new deployment and the permalinks cannot be resolved.

## UsersFilePath

*string*

The path to a file containing a list of credentials for the controllers to use. If present, it is used to automatically upload it to the agents and override the agent's config's own [`UsersFilePath`](config.md/#UsersFilePath).

## PyroscopeSettings

### EnableAppProfiling

*bool*

Enable continuous profiling of all the app instances.

### EnableAgentProfiling

*bool*

Enable continuous profiling of all the agent instances.