confgenerator/fluentbit/modular.go (87 lines of code) (raw):
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package fluentbit provides data structures to represent and generate fluentBit configuration.
package fluentbit
import (
"fmt"
"sort"
"strings"
)
type Component struct {
// Kind is "INPUT", "FILTER", "PARSER", etc.
Kind string
// Config is a set of key-value configuration pairs
Config map[string]string
// OrderedConfig is used for configuration pairs where the
// key can appear in the output fluent bit config multiple times
// and/or the order of the configuration provided is important
OrderedConfig [][2]string
}
func (c Component) generateSection() string {
var lines []string
var maxLen int
for k := range c.Config {
if len(k) > maxLen {
maxLen = len(k)
}
}
for _, line := range c.OrderedConfig {
if len(line[0]) > maxLen {
maxLen = len(line[0])
}
}
addLine := func(k, v string) { lines = append(lines, fmt.Sprintf(" %-*s %s", maxLen, k, v)) }
for k, v := range c.Config {
addLine(k, v)
}
sort.Strings(lines)
// Used for Multiline config where several "rule" lines
// must be placed at the end of a parser config, and when multiple "Parser"
// are provided to one parser filter
for _, line := range c.OrderedConfig {
addLine(line[0], line[1])
}
return fmt.Sprintf("[%s]\n%s\n", c.Kind, strings.Join(lines, "\n"))
}
type ModularConfig struct {
Variables map[string]string
Components []Component
}
const (
outputFileKind = "OPSAGENTOUTPUTFILE"
outputFileName = "filename"
outputFileContents = "contents"
)
const (
MainConfigFileName = "fluent_bit_main.conf"
ParserConfigFileName = "fluent_bit_parser.conf"
)
func outputFileComponent(name, contents string) Component {
return Component{
Kind: outputFileKind,
Config: map[string]string{
outputFileName: name,
outputFileContents: contents,
},
}
}
func (c ModularConfig) Generate() (map[string]string, error) {
files := make(map[string]string)
var parts []string
for k, v := range c.Variables {
parts = append(parts, fmt.Sprintf("@SET %s=%s", k, v))
}
sort.Strings(parts)
// Blank line
parts = append(parts, "")
// TODO: Consider removing this sorting and just outputting the components in native order.
sectionsByKind := map[string][]string{}
for _, c := range c.Components {
if c.Kind == outputFileKind {
files[c.Config[outputFileName]] = c.Config[outputFileContents]
continue
}
out := c.generateSection()
sectionsByKind[c.Kind] = append(sectionsByKind[c.Kind], out)
}
parserParts := append(sectionsByKind["PARSER"], sectionsByKind["MULTILINE_PARSER"]...)
delete(sectionsByKind, "PARSER")
delete(sectionsByKind, "MULTILINE_PARSER")
for _, k := range []string{"SERVICE", "INPUT", "FILTER", "OUTPUT"} {
parts = append(parts, sectionsByKind[k]...)
delete(sectionsByKind, k)
}
if len(sectionsByKind) > 0 {
return nil, fmt.Errorf("unknown fluentbit config sections %+v", sectionsByKind)
}
files[MainConfigFileName] = strings.Join(parts, "\n")
files[ParserConfigFileName] = strings.Join(parserParts, "\n")
return files, nil
}