Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
261
config/migration.go
Normal file
261
config/migration.go
Normal file
|
@ -0,0 +1,261 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/toml"
|
||||
"github.com/influxdata/toml/ast"
|
||||
|
||||
"github.com/influxdata/telegraf/migrations"
|
||||
_ "github.com/influxdata/telegraf/migrations/all" // register all migrations
|
||||
)
|
||||
|
||||
type section struct {
|
||||
name string
|
||||
begin int
|
||||
content *ast.Table
|
||||
raw *bytes.Buffer
|
||||
}
|
||||
|
||||
func splitToSections(root *ast.Table) ([]section, error) {
|
||||
var sections []section
|
||||
for name, elements := range root.Fields {
|
||||
switch name {
|
||||
case "inputs", "outputs", "processors", "aggregators":
|
||||
category, ok := elements.(*ast.Table)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q is not a table (%T)", name, category)
|
||||
}
|
||||
|
||||
for plugin, elements := range category.Fields {
|
||||
tbls, ok := elements.([]*ast.Table)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("elements of \"%s.%s\" is not a list of tables (%T)", name, plugin, elements)
|
||||
}
|
||||
for _, tbl := range tbls {
|
||||
s := section{
|
||||
name: name + "." + tbl.Name,
|
||||
begin: tbl.Line,
|
||||
content: tbl,
|
||||
raw: &bytes.Buffer{},
|
||||
}
|
||||
sections = append(sections, s)
|
||||
}
|
||||
}
|
||||
default:
|
||||
tbl, ok := elements.(*ast.Table)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q is not a table (%T)", name, elements)
|
||||
}
|
||||
s := section{
|
||||
name: name,
|
||||
begin: tbl.Line,
|
||||
content: tbl,
|
||||
raw: &bytes.Buffer{},
|
||||
}
|
||||
sections = append(sections, s)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the TOML elements by begin (line-number)
|
||||
sort.SliceStable(sections, func(i, j int) bool { return sections[i].begin < sections[j].begin })
|
||||
|
||||
return sections, nil
|
||||
}
|
||||
|
||||
func assignTextToSections(data []byte, sections []section) ([]section, error) {
|
||||
// Now assign the raw text to each section
|
||||
if sections[0].begin > 0 {
|
||||
sections = append([]section{{
|
||||
name: "header",
|
||||
begin: 0,
|
||||
raw: &bytes.Buffer{},
|
||||
}}, sections...)
|
||||
}
|
||||
|
||||
var lineno int
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(data))
|
||||
for idx, next := range sections[1:] {
|
||||
var buf bytes.Buffer
|
||||
for lineno < next.begin-1 {
|
||||
if !scanner.Scan() {
|
||||
break
|
||||
}
|
||||
lineno++
|
||||
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if strings.HasPrefix(line, "#") {
|
||||
buf.Write(scanner.Bytes())
|
||||
buf.WriteString("\n")
|
||||
continue
|
||||
} else if buf.Len() > 0 {
|
||||
if _, err := io.Copy(sections[idx].raw, &buf); err != nil {
|
||||
return nil, fmt.Errorf("copying buffer failed: %w", err)
|
||||
}
|
||||
buf.Reset()
|
||||
}
|
||||
|
||||
sections[idx].raw.Write(scanner.Bytes())
|
||||
sections[idx].raw.WriteString("\n")
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("splitting by line failed: %w", err)
|
||||
}
|
||||
|
||||
// If a comment is directly in front of the next section, without
|
||||
// newline, the comment is assigned to the next section.
|
||||
if buf.Len() > 0 {
|
||||
if _, err := io.Copy(sections[idx+1].raw, &buf); err != nil {
|
||||
return nil, fmt.Errorf("copying buffer failed: %w", err)
|
||||
}
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
||||
// Write the remaining to the last section
|
||||
for scanner.Scan() {
|
||||
sections[len(sections)-1].raw.Write(scanner.Bytes())
|
||||
sections[len(sections)-1].raw.WriteString("\n")
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("splitting by line failed: %w", err)
|
||||
}
|
||||
return sections, nil
|
||||
}
|
||||
|
||||
func ApplyMigrations(data []byte) ([]byte, uint64, error) {
|
||||
root, err := toml.Parse(data)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("parsing failed: %w", err)
|
||||
}
|
||||
|
||||
// Split the configuration into sections containing the location
|
||||
// in the file.
|
||||
sections, err := splitToSections(root)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("splitting to sections failed: %w", err)
|
||||
}
|
||||
if len(sections) == 0 {
|
||||
return nil, 0, errors.New("no TOML configuration found")
|
||||
}
|
||||
|
||||
// Assign the configuration text to the corresponding segments
|
||||
sections, err = assignTextToSections(data, sections)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("assigning text failed: %w", err)
|
||||
}
|
||||
|
||||
var applied uint64
|
||||
// Do the actual global section migration(s)
|
||||
for idx, s := range sections {
|
||||
if strings.Contains(s.name, ".") {
|
||||
continue
|
||||
}
|
||||
log.Printf("D! applying global migrations to section %q in line %d...", s.name, s.begin)
|
||||
for _, migrate := range migrations.GlobalMigrations {
|
||||
result, msg, err := migrate(s.name, s.content)
|
||||
if err != nil {
|
||||
if errors.Is(err, migrations.ErrNotApplicable) {
|
||||
continue
|
||||
}
|
||||
return nil, 0, fmt.Errorf("migrating options of %q (line %d) failed: %w", s.name, s.begin, err)
|
||||
}
|
||||
if msg != "" {
|
||||
log.Printf("I! Global section %q in line %d: %s", s.name, s.begin, msg)
|
||||
}
|
||||
s.raw = bytes.NewBuffer(result)
|
||||
applied++
|
||||
}
|
||||
sections[idx] = s
|
||||
}
|
||||
|
||||
// Do the actual plugin migration(s)
|
||||
for idx, s := range sections {
|
||||
migrate, found := migrations.PluginMigrations[s.name]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("D! migrating plugin %q in line %d...", s.name, s.begin)
|
||||
result, msg, err := migrate(s.content)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("migrating %q (line %d) failed: %w", s.name, s.begin, err)
|
||||
}
|
||||
if msg != "" {
|
||||
log.Printf("I! Plugin %q in line %d: %s", s.name, s.begin, msg)
|
||||
}
|
||||
s.raw = bytes.NewBuffer(result)
|
||||
tbl, err := toml.Parse(s.raw.Bytes())
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("reparsing migrated %q (line %d) failed: %w", s.name, s.begin, err)
|
||||
}
|
||||
s.content = tbl
|
||||
sections[idx] = s
|
||||
applied++
|
||||
}
|
||||
|
||||
// Do the actual plugin option migration(s)
|
||||
for idx, s := range sections {
|
||||
migrate, found := migrations.PluginOptionMigrations[s.name]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("D! migrating options of plugin %q in line %d...", s.name, s.begin)
|
||||
result, msg, err := migrate(s.content)
|
||||
if err != nil {
|
||||
if errors.Is(err, migrations.ErrNotApplicable) {
|
||||
continue
|
||||
}
|
||||
return nil, 0, fmt.Errorf("migrating options of %q (line %d) failed: %w", s.name, s.begin, err)
|
||||
}
|
||||
if msg != "" {
|
||||
log.Printf("I! Plugin %q in line %d: %s", s.name, s.begin, msg)
|
||||
}
|
||||
s.raw = bytes.NewBuffer(result)
|
||||
sections[idx] = s
|
||||
applied++
|
||||
}
|
||||
|
||||
// Do general migrations applying to all plugins
|
||||
for idx, s := range sections {
|
||||
parts := strings.Split(s.name, ".")
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
log.Printf("D! applying general migrations to plugin %q in line %d...", s.name, s.begin)
|
||||
category, name := parts[0], parts[1]
|
||||
for _, migrate := range migrations.GeneralMigrations {
|
||||
result, msg, err := migrate(category, name, s.content)
|
||||
if err != nil {
|
||||
if errors.Is(err, migrations.ErrNotApplicable) {
|
||||
continue
|
||||
}
|
||||
return nil, 0, fmt.Errorf("migrating options of %q (line %d) failed: %w", s.name, s.begin, err)
|
||||
}
|
||||
if msg != "" {
|
||||
log.Printf("I! Plugin %q in line %d: %s", s.name, s.begin, msg)
|
||||
}
|
||||
s.raw = bytes.NewBuffer(result)
|
||||
applied++
|
||||
}
|
||||
sections[idx] = s
|
||||
}
|
||||
|
||||
// Reconstruct the config file from the sections
|
||||
var buf bytes.Buffer
|
||||
for _, s := range sections {
|
||||
_, err = s.raw.WriteTo(&buf)
|
||||
if err != nil {
|
||||
return nil, applied, fmt.Errorf("joining output failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return buf.Bytes(), applied, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue