Skip to content

Commit

Permalink
Add the option to generate the template into a file
Browse files Browse the repository at this point in the history
Part of elastic#3654.
  • Loading branch information
Tudor Golubenco committed May 16, 2017
1 parent b2ccdcb commit dabc10c
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 3 deletions.
26 changes: 24 additions & 2 deletions libbeat/beat/beat.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,30 @@ func (b *Beat) registerTemplateLoading() error {
}
}

esConfig := b.Config.Output["elasticsearch"]
// Check if outputting to file is enabled, and output to file if it is
if b.Config.Template != nil && b.Config.Template.Enabled() {
var cfg template.TemplateConfig
err := b.Config.Template.Unpack(&cfg)
if err != nil {
return fmt.Errorf("unpacking template config fails: %v", err)
}
if len(cfg.OutputToFile.Path) > 0 {
// output to file is enabled
loader, err := template.NewLoader(b.Config.Template, nil, b.Info)
if err != nil {
return fmt.Errorf("Error creating Elasticsearch template loader: %v", err)
}
err = loader.Generate()
if err != nil {
return fmt.Errorf("Error generating template: %v", err)
}

// XXX: Should we kill the Beat here or just continue?
return fmt.Errorf("Stopping after successfully writing the template to the file.")
}
}

esConfig := b.Config.Output["elasticsearch"]
// Loads template by default if esOutput is enabled
if (b.Config.Template == nil && esConfig.Enabled()) || (b.Config.Template != nil && b.Config.Template.Enabled()) {
if esConfig == nil || !esConfig.Enabled() {
Expand All @@ -487,7 +509,7 @@ func (b *Beat) registerTemplateLoading() error {

loader, err := template.NewLoader(b.Config.Template, esClient, b.Info)
if err != nil {
return fmt.Errorf("Error creating Elasticsearch template: %v", err)
return fmt.Errorf("Error creating Elasticsearch template loader: %v", err)
}

err = loader.Load()
Expand Down
9 changes: 8 additions & 1 deletion libbeat/template/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ type TemplateConfig struct {
Name string `config:"name"`
Fields string `config:"fields"`
Overwrite bool `config:"overwrite"`
OutputToFile string `config:"output_to_file"`
Settings templateSettings `config:"settings"`
OutputToFile OutputToFile `config:"output_to_file"`
}

// OutputToFile contains the configuration options for generating
// and writing the template into a file.
type OutputToFile struct {
Path string `config:"path"`
Version string `config:"version"`
}

type templateSettings struct {
Expand Down
37 changes: 37 additions & 0 deletions libbeat/template/load.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package template

import (
"encoding/json"
"fmt"
"io/ioutil"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/logp"
Expand Down Expand Up @@ -80,6 +82,41 @@ func (l *Loader) Load() error {
return nil
}

func (l *Loader) Generate() error {
if l.config.OutputToFile.Version == "" {
l.config.OutputToFile.Version = l.beatInfo.Version
}

if l.config.Name == "" {
l.config.Name = l.beatInfo.Beat
}

tmpl, err := New(l.beatInfo.Version, l.config.OutputToFile.Version, l.config.Name, l.config.Settings)
if err != nil {
return fmt.Errorf("error creating template instance: %v", err)
}

fieldsPath := paths.Resolve(paths.Config, l.config.Fields)

output, err := tmpl.Load(fieldsPath)
if err != nil {
return fmt.Errorf("error creating template from file %s: %v", fieldsPath, err)
}

jsonBytes, err := json.MarshalIndent(output, "", " ")
if err != nil {
return fmt.Errorf("error marshaling template: %v", err)
}

err = ioutil.WriteFile(l.config.OutputToFile.Path, jsonBytes, 0644)
if err != nil {
return fmt.Errorf("error writing to file %s: %v", l.config.OutputToFile.Path, err)
}

logp.Info("Template for Elasticsearch %s written to: %s", l.config.OutputToFile.Version, l.config.OutputToFile.Path)
return nil
}

// LoadTemplate loads a template into Elasticsearch overwriting the existing
// template if it exists. If you wish to not overwrite an existing template
// then use CheckTemplate prior to calling this method.
Expand Down
112 changes: 112 additions & 0 deletions libbeat/template/load_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// +build !integration

package template

import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/version"
"github.com/stretchr/testify/assert"
)

func TestGenerateTemplate(t *testing.T) {

// Load template
absPath, err := filepath.Abs("../")
assert.NotNil(t, absPath)
assert.Nil(t, err)

beatInfo := common.BeatInfo{
Beat: "testbeat",
Version: version.GetDefaultVersion(),
}

dir, err := ioutil.TempDir("", "test-template")
assert.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "template.json")

config := newConfigFrom(t, TemplateConfig{
Enabled: true,
Fields: absPath + "/fields.yml",
OutputToFile: OutputToFile{
Path: path,
},
})

loader, err := NewLoader(config, nil, beatInfo)
assert.NoError(t, err)

err = loader.Generate()
assert.NoError(t, err)

// Read it back to check it
fp, err := os.Open(path)
assert.NoError(t, err)
jsonParser := json.NewDecoder(fp)
var parsed common.MapStr
err = jsonParser.Decode(&parsed)
assert.NoError(t, err)

val, err := parsed.GetValue("mappings._default_._meta.version")
assert.NoError(t, err)
assert.Equal(t, val.(string), version.GetDefaultVersion())

}

func TestGenerateTemplateWithVersion(t *testing.T) {

// Load template
absPath, err := filepath.Abs("../")
assert.NotNil(t, absPath)
assert.Nil(t, err)

beatInfo := common.BeatInfo{
Beat: "testbeat",
Version: version.GetDefaultVersion(),
}

dir, err := ioutil.TempDir("", "test-template")
assert.NoError(t, err)
defer os.RemoveAll(dir)
path := filepath.Join(dir, "template.json")

config := newConfigFrom(t, TemplateConfig{
Enabled: true,
Fields: absPath + "/fields.yml",
OutputToFile: OutputToFile{
Path: path,
Version: "2.4.0",
},
})

loader, err := NewLoader(config, nil, beatInfo)
assert.NoError(t, err)

err = loader.Generate()
assert.NoError(t, err)

// Read it back to check it
fp, err := os.Open(path)
assert.NoError(t, err)
jsonParser := json.NewDecoder(fp)
var parsed common.MapStr
err = jsonParser.Decode(&parsed)
assert.NoError(t, err)

// check a setting specific to that version
val, err := parsed.GetValue("mappings._default_._all.norms.enabled")
assert.NoError(t, err)
assert.Equal(t, val.(bool), false)
}

func newConfigFrom(t *testing.T, from interface{}) *common.Config {
cfg, err := common.NewConfigFrom(from)
assert.NoError(t, err)
return cfg
}

0 comments on commit dabc10c

Please sign in to comment.