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

feat: doctor should handle embedded exporters #3258

Merged
merged 1 commit into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
49 changes: 45 additions & 4 deletions cmd/tools/doctor/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,20 +422,27 @@ func checkExportersExist(config conf.HarvestConfig) validation {
return valid
}

// checkUniquePromPorts checks that all Prometheus exporters
// which specify a port, do so uniquely
// checkUniquePromPorts checks that all Prometheus exporters, which specify a port, do so uniquely.
// Embedded exporters can conflict with non-embedded exporters, but not with each other.
func checkUniquePromPorts(config conf.HarvestConfig) validation {
if config.Exporters == nil {
return validation{}
}
// Add all exporters that have a port to a
// map of portNum -> list of names
seen := make(map[int][]string)
var embeddedExporters []conf.ExporterDef

for name, exporter := range config.Exporters {
// ignore configuration with both port and portrange defined. PortRange takes precedence
if exporter.Port == nil || exporter.Type != "Prometheus" || exporter.PortRange != nil {
continue
}
// Ignore embedded exporters
if exporter.IsEmbedded {
embeddedExporters = append(embeddedExporters, conf.ExporterDef{Exporter: exporter, Name: name})
continue
}
previous := seen[*exporter.Port]
previous = append(previous, name)
seen[*exporter.Port] = previous
Expand All @@ -462,10 +469,26 @@ func checkUniquePromPorts(config conf.HarvestConfig) validation {
continue
}
valid.isValid = false
valid.invalid = append(valid.invalid, exporterNames...)
break
}

// Check that embedded exports do not conflict with each other
embeddedPorts := make(map[int][]string)
for _, embeddedExporter := range embeddedExporters {
// Check if the embedded exporter has a port
if embeddedExporter.Port == nil {
continue
}
// Check if the port is unique
previous := embeddedPorts[*embeddedExporter.Port]
previous = append(previous, embeddedExporter.Name)
embeddedPorts[*embeddedExporter.Port] = previous
if len(previous) > 1 {
valid.isValid = false
break
}
}

if !valid.isValid {
fmt.Printf("%s: Exporter PromPort conflict\n", color.Colorize("Error", color.Red))
fmt.Println(" Prometheus exporters must specify unique ports. Change the following exporters to use unique ports:")
Expand All @@ -474,7 +497,25 @@ func checkUniquePromPorts(config conf.HarvestConfig) validation {
continue
}
names := strings.Join(exporterNames, ", ")
fmt.Printf(" port: [%s] duplicateExporters: [%s]\n", color.Colorize(port, color.Red), color.Colorize(names, color.Yellow))
valid.invalid = append(valid.invalid, exporterNames...)
fmt.Printf(" port: [%s] duplicate exporters: [%s]\n", color.Colorize(port, color.Red), color.Colorize(names, color.Yellow))
}
for port, exporterNames := range embeddedPorts {
if len(exporterNames) == 1 {
continue
}
pollerNames := make([]string, 0, len(exporterNames))
for _, exporterName := range exporterNames {
index := strings.LastIndex(exporterName, "-")
if index == -1 {
pollerNames = append(pollerNames, exporterName)
continue
}
pollerNames = append(pollerNames, exporterName[:index])
}
names := strings.Join(pollerNames, ", ")
valid.invalid = append(valid.invalid, exporterNames...)
fmt.Printf(" port: [%s] duplicate embedded exporters for pollers: [%s]\n", color.Colorize(port, color.Red), color.Colorize(names, color.Yellow))
}
fmt.Println()
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/tools/doctor/doctor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func TestUniquePromPorts(t *testing.T) {
if valid.isValid {
t.Fatal(`expected isValid to be false since there are duplicate prom ports, actual was isValid=true`)
}
if len(valid.invalid) != 2 {
if len(valid.invalid) != 4 {
t.Fatalf(`expected checkUniquePromPorts to return 2 invalid results, actual was %s`, valid.invalid)
}
}
Expand Down
10 changes: 10 additions & 0 deletions cmd/tools/doctor/testdata/testConfig.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,14 @@ Pollers:
username: admin
password: '#pass' # you can use single or double quotes to escape #

poller-with-embedded-exporter:
exporters:
- exporter: Prometheus
port: 2000

poller-with-embedded-exporter2:
exporters:
- exporter: Prometheus
port: 2000

ll: grafana_api_token grafana_api_token
4 changes: 2 additions & 2 deletions integration/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ require (
)

require (
github.com/ebitengine/purego v0.8.0 // indirect
github.com/ebitengine/purego v0.8.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
Expand All @@ -26,7 +26,7 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shirou/gopsutil/v4 v4.24.9 // indirect
github.com/shirou/gopsutil/v4 v4.24.10 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
Expand Down
8 changes: 4 additions & 4 deletions integration/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ github.com/carlmjohnson/requests v0.24.2/go.mod h1:duYA/jDnyZ6f3xbcF5PpZ9N8clgop
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
Expand Down Expand Up @@ -39,8 +39,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil/v4 v4.24.9 h1:KIV+/HaHD5ka5f570RZq+2SaeFsb/pq+fp2DGNWYoOI=
github.com/shirou/gopsutil/v4 v4.24.9/go.mod h1:3fkaHNeYsUFCGZ8+9vZVWtbyM1k2eRnlL+bWO8Bxa/Q=
github.com/shirou/gopsutil/v4 v4.24.10 h1:7VOzPtfw/5YDU+jLEoBwXwxJbQetULywoSV4RYY7HkM=
github.com/shirou/gopsutil/v4 v4.24.10/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down
4 changes: 2 additions & 2 deletions pkg/color/color.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ func DetectConsole(option string) {
}
}

func Colorize(s interface{}, color string) string {
func Colorize(s any, color string) string {
if withColor {
return fmt.Sprintf("%s%v\x1b[0m", color, s)
}
return fmt.Sprintf("%s", s)
return fmt.Sprintf("%v", s)
}
16 changes: 9 additions & 7 deletions pkg/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ func fixupExporters() {
for _, pollerName := range Config.PollersOrdered {
poller := Config.Pollers[pollerName]
for i, e := range poller.ExporterDefs {
exporterName := e.name
exporterName := e.Name
if exporterName == "" {
// This is an embedded exporter, synthesize a name for it
e.Exporter.IsEmbedded = true
exporterName = fmt.Sprintf("%s-%d", pollerName, i)
Config.Exporters[exporterName] = e.Exporter
}
Expand Down Expand Up @@ -498,8 +499,8 @@ type CertificateScript struct {
Timeout string `yaml:"timeout,omitempty"`
}

type ExportDef struct {
name string
type ExporterDef struct {
Name string
Exporter
}

Expand All @@ -509,7 +510,7 @@ type Recorder struct {
KeepLast string `yaml:"keep_last,omitempty"` // number of records to keep before overwriting
}

func (e *ExportDef) UnmarshalYAML(n *yaml.Node) error {
func (e *ExporterDef) UnmarshalYAML(n *yaml.Node) error {
if n.Kind == yaml.MappingNode {
var aExporter *Exporter
err := n.Decode(&aExporter)
Expand All @@ -518,7 +519,7 @@ func (e *ExportDef) UnmarshalYAML(n *yaml.Node) error {
}
e.Exporter = *aExporter
} else if n.Kind == yaml.ScalarNode && n.ShortTag() == "!!str" {
e.name = n.Value
e.Name = n.Value
}
return nil
}
Expand All @@ -536,7 +537,7 @@ type Poller struct {
CredentialsFile string `yaml:"credentials_file,omitempty"`
CredentialsScript CredentialsScript `yaml:"credentials_script,omitempty"`
Datacenter string `yaml:"datacenter,omitempty"`
ExporterDefs []ExportDef `yaml:"exporters,omitempty"`
ExporterDefs []ExporterDef `yaml:"exporters,omitempty"`
Exporters []string `yaml:"-"`
IsKfs bool `yaml:"is_kfs,omitempty"`
Labels *[]map[string]string `yaml:"labels,omitempty"`
Expand Down Expand Up @@ -698,7 +699,8 @@ type Exporter struct {
ClientTimeout *string `yaml:"client_timeout,omitempty"`
Version *string `yaml:"version,omitempty"`

IsTest bool // true when run from unit tests
IsTest bool // true when run from unit tests
IsEmbedded bool // true when the exporter is embedded in a poller
}

type Pollers struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/tree/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func TestHarvestConfigImportYaml(t *testing.T) {
}
}

want = 12
want = 14
got = 0
if pollers := template.GetChildS("Pollers"); pollers != nil {
for range pollers.GetChildren() {
Expand Down