forked from influxdata/telegraf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: tool to build custom Telegraf builds (influxdata#11524)
- Loading branch information
Showing
13 changed files
with
783 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
//go:build !custom | ||
|
||
package internal | ||
|
||
const Customized = "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
//go:build custom | ||
|
||
package internal | ||
|
||
const Customized = " (customized)" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# Telegraf customization tool | ||
|
||
Telegraf's `custom_builder` is a tool to select the plugins compiled into the | ||
Telegraf binary. By doing so, Telegraf can become smaller, saving both disk | ||
space and memory if only a sub-set of plugins is selected. | ||
|
||
## Building | ||
|
||
To build `custom_builder` run the following command: | ||
|
||
```shell | ||
# make build_tools | ||
``` | ||
|
||
The resulting binary is located in the `tools/custom_builder` folder. | ||
|
||
## Running | ||
|
||
The easiest way of building a customized Telegraf is to use your | ||
Telegraf configuration file(s). Assuming your configuration is | ||
in `/etc/telegraf/telegraf.conf` you can run | ||
|
||
```shell | ||
# ./tools/custom_builder/custom_builder --config /etc/telegraf/telegraf.conf | ||
``` | ||
|
||
to build a Telegraf binary tailored to your configuration. | ||
You can also specify a configuration directory similar to | ||
Telegraf itself. To additionally use the configurations in | ||
`/etc/telegraf/telegraf.d` run | ||
|
||
```shell | ||
# ./tools/custom_builder/custom_builder \ | ||
--config /etc/telegraf/telegraf.conf \ | ||
--config-dir /etc/telegraf/telegraf.d | ||
``` | ||
|
||
Configurations can also be retrieved from remote locations just | ||
like for Telegraf. | ||
|
||
```shell | ||
# ./tools/custom_builder/custom_builder --config http://myserver/telegraf.conf | ||
``` | ||
|
||
will download the configuration from `myserver`. | ||
|
||
The `--config` and `--config-dir` option can be used multiple times. | ||
In case you want to deploy Telegraf to multiple systems with | ||
different configurations, simply specify the super-set of all | ||
configurations you have. `custom_builder` will figure out the list | ||
for you | ||
|
||
```shell | ||
# ./tools/custom_builder/custom_builder \ | ||
--config system1/telegraf.conf \ | ||
--config system2/telegraf.conf \ | ||
--config ... \ | ||
--config systemN/telegraf.conf \ | ||
--config-dir system1/telegraf.d \ | ||
--config-dir system2/telegraf.d \ | ||
--config-dir ... \ | ||
--config-dir systemN/telegraf.d | ||
``` | ||
|
||
The Telegraf customization uses | ||
[Golang's build-tags](https://pkg.go.dev/go/build#hdr-Build_Constraints) to | ||
select the set of plugins. To see which tags are set use the `--tags` flag. | ||
|
||
To get more help run | ||
|
||
```shell | ||
# ./tools/custom_builder/custom_builder --help | ||
``` | ||
|
||
## Notes | ||
|
||
Please make sure to include all `parsers` you intend to use and check the | ||
enabled-plugins list. | ||
|
||
Additional plugins can potentially be enabled automatically due to | ||
dependencies without being shown in the enabled-plugins list. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/influxdata/telegraf/config" | ||
"github.com/influxdata/toml" | ||
"github.com/influxdata/toml/ast" | ||
) | ||
|
||
type pluginState map[string]bool | ||
type selection map[string]pluginState | ||
|
||
func ImportConfigurations(files, dirs []string) (*selection, int, error) { | ||
sel := selection(make(map[string]pluginState)) | ||
|
||
// Initialize the categories | ||
for _, category := range categories { | ||
sel[category] = make(map[string]bool) | ||
} | ||
|
||
// Gather all configuration files | ||
var filenames []string | ||
filenames = append(filenames, files...) | ||
|
||
for _, dir := range dirs { | ||
// Walk the directory and get the packages | ||
elements, err := os.ReadDir(dir) | ||
if err != nil { | ||
return nil, 0, fmt.Errorf("reading directory %q failed: %w", dir, err) | ||
} | ||
|
||
for _, element := range elements { | ||
if element.IsDir() || filepath.Ext(element.Name()) != ".conf" { | ||
continue | ||
} | ||
|
||
filenames = append(filenames, filepath.Join(dir, element.Name())) | ||
} | ||
} | ||
if len(filenames) == 0 { | ||
return &sel, 0, errors.New("no configuration files given or found") | ||
} | ||
|
||
// Do the actual import | ||
err := sel.importFiles(filenames) | ||
return &sel, len(filenames), err | ||
} | ||
|
||
func (s *selection) Filter(p packageCollection) (*packageCollection, error) { | ||
enabled := packageCollection{ | ||
packages: map[string][]packageInfo{}, | ||
} | ||
|
||
for category, pkgs := range p.packages { | ||
var categoryEnabledPackages []packageInfo | ||
settings := (*s)[category] | ||
for _, pkg := range pkgs { | ||
if _, found := settings[pkg.Plugin]; found { | ||
categoryEnabledPackages = append(categoryEnabledPackages, pkg) | ||
} | ||
} | ||
enabled.packages[category] = categoryEnabledPackages | ||
} | ||
|
||
// Make sure we update the list of default parsers used by | ||
// the remaining packages | ||
enabled.FillDefaultParsers() | ||
|
||
// If the user did not configure any parser, we want to include | ||
// the default parsers if any to preserve a functional set of | ||
// plugins. | ||
if len(enabled.packages["parsers"]) == 0 && len(enabled.defaultParsers) > 0 { | ||
var parsers []packageInfo | ||
for _, pkg := range p.packages["parsers"] { | ||
for _, name := range enabled.defaultParsers { | ||
if pkg.Plugin == name { | ||
parsers = append(parsers, pkg) | ||
break | ||
} | ||
} | ||
} | ||
enabled.packages["parsers"] = parsers | ||
} | ||
|
||
return &enabled, nil | ||
} | ||
|
||
func (s *selection) importFiles(configurations []string) error { | ||
for _, cfg := range configurations { | ||
buf, err := config.LoadConfigFile(cfg) | ||
if err != nil { | ||
return fmt.Errorf("reading %q failed: %v", cfg, err) | ||
} | ||
|
||
if err := s.extractPluginsFromConfig(buf); err != nil { | ||
return fmt.Errorf("extracting plugins from %q failed: %v", cfg, err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *selection) extractPluginsFromConfig(buf []byte) error { | ||
table, err := toml.Parse(trimBOM(buf)) | ||
if err != nil { | ||
return fmt.Errorf("parsing TOML failed: %w", err) | ||
} | ||
|
||
for category, subtbl := range table.Fields { | ||
categoryTbl, ok := subtbl.(*ast.Table) | ||
if !ok { | ||
continue | ||
} | ||
|
||
if _, found := (*s)[category]; !found { | ||
continue | ||
} | ||
|
||
for name, data := range categoryTbl.Fields { | ||
(*s)[category][name] = true | ||
|
||
// We need to check the data_format field to get all required parsers | ||
switch category { | ||
case "inputs", "processors": | ||
pluginTables, ok := data.([]*ast.Table) | ||
if !ok { | ||
continue | ||
} | ||
for _, subsubtbl := range pluginTables { | ||
for field, fieldData := range subsubtbl.Fields { | ||
if field != "data_format" { | ||
continue | ||
} | ||
kv := fieldData.(*ast.KeyValue) | ||
name := kv.Value.(*ast.String) | ||
(*s)["parsers"][name.Value] = true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func trimBOM(f []byte) []byte { | ||
return bytes.TrimPrefix(f, []byte("\xef\xbb\xbf")) | ||
} |
Oops, something went wrong.