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

Port fields.yml collector to Golang #6911

Merged
merged 25 commits into from
May 30, 2018
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
1 change: 1 addition & 0 deletions CHANGELOG-developer.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The list below covers the major changes between 6.3.0 and master only.

- The beat.Pipeline is now passed to cfgfile.RunnerFactory. Beats using libbeat for module reloading or autodiscovery need to be adapted. {pull}7018[7017]
- Moving of TLS helper functions and structs from `output/tls` to `tlscommon`. {pull}7054[7054]
- Port fields.yml collector to Golang {pull}6911[6911]

==== Bugfixes

Expand Down
8 changes: 1 addition & 7 deletions auditbeat/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ GOX_OS?=linux windows ## @Building List of all OS to be supported by "make cross
DEV_OS?=linux
TESTING_ENVIRONMENT?=snapshot-noxpack
ES_BEATS?=..
FIELDS_FILE_PATH=module

# Path to the libbeat Makefile
include ${ES_BEATS}/libbeat/scripts/Makefile
Expand Down Expand Up @@ -58,13 +59,6 @@ before-build:
.PHONY: collect
collect: fields collect-docs configs kibana

# Collects all module and metricset fields
.PHONY: fields
fields: python-env
@mkdir -p _meta
@cp _meta/fields.common.yml _meta/fields.generated.yml
@${PYTHON_ENV}/bin/python ${ES_BEATS}/metricbeat/scripts/fields_collector.py >> _meta/fields.generated.yml

# Collects all module configs
.PHONY: configs
configs: python-env
Expand Down
2 changes: 1 addition & 1 deletion auditbeat/include/fields.go

Large diffs are not rendered by default.

9 changes: 2 additions & 7 deletions filebeat/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ SYSTEM_TESTS?=true
TEST_ENVIRONMENT?=true
GOX_FLAGS=-arch="amd64 386 arm ppc64 ppc64le"
ES_BEATS?=..
FIELDS_FILE_PATH=module
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this only support one path? I could see especially in libbeat or filebeat that a module, processor and inputs have fields.yml.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it can be changed easily to support lists.



include ${ES_BEATS}/libbeat/scripts/Makefile

Expand All @@ -19,13 +21,6 @@ kibana:
@mkdir -p _meta/kibana
@-cp -r module/*/_meta/kibana _meta/

# Collects all module and dataset fields
.PHONY: fields
fields: python-env
@mkdir -p _meta/
@cp ${ES_BEATS}/filebeat/_meta/fields.common.yml _meta/fields.generated.yml
@${PYTHON_ENV}/bin/python ${ES_BEATS}/metricbeat/scripts/fields_collector.py >> _meta/fields.generated.yml

# Collects all modules files to be packaged in a temporary folder
.PHONY: modules
modules:
Expand Down
2 changes: 1 addition & 1 deletion filebeat/include/fields.go

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions generator/beat/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
override FIELDS_FILE_PATH=
export FIELDS_FILE_PATH

include ../common/Makefile
2 changes: 1 addition & 1 deletion generator/beat/{beat}/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ before-build:

# Collects all dependencies and then calls update
.PHONY: collect
collect:
collect: fields
1 change: 1 addition & 0 deletions generator/common/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ BEAT_PATH=${BUILD_DIR}/src/beatpath/testbeat
ES_BEATS=${GOPATH}/src/github.com/elastic/beats
PREPARE_COMMAND?=


# Runs test build for mock beat
.PHONY: test
test: prepare-test
Expand Down
9 changes: 8 additions & 1 deletion generator/metricbeat/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
BEAT_TYPE=metricbeat
PREPARE_COMMAND=MODULE=elastic METRICSET=test make create-metricset ;
PREPARE_COMMAND=MODULE=elastic METRICSET=test make create-metricset ; FIELDS_FILE_PATH=module
override FIELDS_FILE_PATH=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these 2 lines exactly doing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This overrides FIELDS_FILE_PATH coming from the Makefile of Metricbeat. The problem is that the variable is already set, and the only way I have found to override it is this kind of "ugly" way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As auditbeat depends on Metricbeat, would it then be need there too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but only if the FIELDS_FILE_PATH is different from Metricbeat. But both Beats store their modules under module, so there is no need to add that variable to the Makefile of Auditbeat yet.

export FIELDS_FILE_PATH


include ../common/Makefile

prepare-test:: python-env

mkdir -p ${BEAT_PATH}/scripts
rsync -a --exclude=build ${PWD}/../../metricbeat/scripts/generate_imports_helper.py ${BEAT_PATH}/scripts

# Collects all dependencies and then calls update
.PHONY: collect
collect: fields
8 changes: 1 addition & 7 deletions heartbeat/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ BEAT_PACKAGE_NAME=heartbeat-elastic
BEAT_DESCRIPTION?=Ping remote services for availability and log results to Elasticsearch or send to Logstash.
SYSTEM_TESTS=true
TEST_ENVIRONMENT=false
FIELDS_FILE_PATH=monitors/active

# Path to the libbeat Makefile
-include ../libbeat/scripts/Makefile
Expand All @@ -16,13 +17,6 @@ before-build:
.PHONY: collect
collect: fields imports

# Collects all module and metricset fields
.PHONY: fields
fields:
@mkdir -p _meta/
@cp ${ES_BEATS}/heartbeat/_meta/fields.common.yml _meta/fields.generated.yml
@cat ${ES_BEATS}/heartbeat/monitors/active/*/_meta/fields.yml >> _meta/fields.generated.yml

# Generate imports for all monitors
.PHONY: imports
imports: python-env
Expand Down
9 changes: 2 additions & 7 deletions libbeat/Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
BEAT_NAME=libbeat
TEST_ENVIRONMENT?=true
SYSTEM_TESTS=true
FIELDS_FILE_PATH=processors

include scripts/Makefile

# Collects all fields from processors
.PHONY: fields
fields:
@cp _meta/fields.common.yml _meta/fields.generated.yml
@cat processors/*/_meta/fields.yml >> _meta/fields.generated.yml

# Collects all dependencies and then calls update
.PHONY: collect
collect: fields
collect: libbeat_fields
149 changes: 149 additions & 0 deletions libbeat/generator/fields/fields.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package fields

import (
"bufio"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
)

var (
generatedFieldsYml = filepath.Join("_meta", "fields.generated.yml")
)

// YmlFile holds the info on files and how to write them into the global fields.yml
type YmlFile struct {
Path string
Indent int
}

func collectBeatFiles(beatPath string, fieldFiles []*YmlFile) ([]*YmlFile, error) {
commonFields := filepath.Join(beatPath, "_meta", "fields.common.yml")
_, err := os.Stat(commonFields)
if os.IsNotExist(err) {
return fieldFiles, nil
} else if err != nil {
return nil, err
}

files := []*YmlFile{
&YmlFile{
Path: commonFields,
Indent: 0,
},
}

return append(files, fieldFiles...), nil
}

func writeGeneratedFieldsYml(beatsPath string, fieldFiles []*YmlFile) error {
outPath := path.Join(beatsPath, generatedFieldsYml)
f, err := os.Create(outPath)
if err != nil {
return err
}
defer f.Close()

fw := bufio.NewWriter(f)
for _, p := range fieldFiles {
ff, err := os.Open(p.Path)
if err != nil {
return err
}
defer ff.Close()

fs := bufio.NewScanner(ff)
for fs.Scan() {
err = writeIndentedLine(fw, fs.Text()+"\n", p.Indent)
if err != nil {
return err
}

}
if err := fs.Err(); err != nil {
return err
}
}
return nil
}

func writeIndentedLine(fw *bufio.Writer, l string, indent int) error {
ll := strings.Repeat(" ", indent) + l
fmt.Fprint(fw, ll)
return fw.Flush()
}

// Generate collects fields.yml files and concatenates them into one global file.
func Generate(esBeatsPath, beatPath string, files []*YmlFile) error {
files, err := collectBeatFiles(beatPath, files)
if err != nil {
return err
}

err = writeGeneratedFieldsYml(beatPath, files)
if err != nil {
return err
}

return AppendFromLibbeat(esBeatsPath, beatPath)
}

// AppendFromLibbeat appends fields.yml of libbeat to the fields.yml
func AppendFromLibbeat(esBeatsPath, beatPath string) error {
fieldsMetaPath := path.Join(beatPath, "_meta", "fields.yml")
generatedPath := path.Join(beatPath, generatedFieldsYml)

err := createIfNotExists(fieldsMetaPath, generatedPath)
if err != nil {
return err
}

if isLibbeat(beatPath) {
out := filepath.Join(esBeatsPath, "libbeat", "fields.yml")
return copyFileWithFlag(generatedPath, out, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
}

libbeatPath := filepath.Join(esBeatsPath, "libbeat", generatedFieldsYml)
out := filepath.Join(beatPath, "fields.yml")
err = copyFileWithFlag(libbeatPath, out, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
if err != nil {
return err
}
return copyFileWithFlag(generatedPath, out, os.O_WRONLY|os.O_APPEND)
}

func isLibbeat(beatPath string) bool {
return filepath.Base(beatPath) == "libbeat"
}

func createIfNotExists(inPath, outPath string) error {
_, err := os.Stat(outPath)
if os.IsNotExist(err) {
err := copyFileWithFlag(inPath, outPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
if err != nil {
fmt.Println("Cannot find _meta/fields.yml")
}
return nil
}
return err
}

func copyFileWithFlag(in, out string, flag int) error {
input, err := ioutil.ReadFile(in)
if err != nil {
return err
}

output, err := os.OpenFile(out, flag, 0644)
if err != nil {
return err
}
defer output.Close()

_, err = output.Write(input)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to set permissions somewhere here to 644?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

644 or 664?

return err

}
74 changes: 74 additions & 0 deletions libbeat/generator/fields/module_fields_collector.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package fields

import (
"io/ioutil"
"os"
"path/filepath"
)

var indentByModule = map[string]int{
"processors": 0,
"module": 8,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit a pity that libbeat has knowledge here outside the scope of libbeat. But probably best way to go for now.

"active": 8,
"protos": 8,
}

// CollectModuleFiles looks for fields.yml files under the
// specified root directory
func CollectModuleFiles(root string) ([]*YmlFile, error) {
modules, err := ioutil.ReadDir(root)
if err != nil {
return nil, err
}

var files []*YmlFile
for _, m := range modules {
f, err := collectFiles(m, root)
if err != nil {
return nil, err
}
files = append(files, f...)
}

return files, nil
}

func collectFiles(module os.FileInfo, modulesPath string) ([]*YmlFile, error) {
if !module.IsDir() {
return nil, nil
}

var files []*YmlFile
fieldsYmlPath := filepath.Join(modulesPath, module.Name(), "_meta", "fields.yml")
if _, err := os.Stat(fieldsYmlPath); !os.IsNotExist(err) {
files = append(files, &YmlFile{
Path: fieldsYmlPath,
Indent: 0,
})
} else if !os.IsNotExist(err) && err != nil {
return nil, err
}

modulesRoot := filepath.Base(modulesPath)
sets, err := ioutil.ReadDir(filepath.Join(modulesPath, module.Name()))
if err != nil {
return nil, err
}

for _, s := range sets {
if !s.IsDir() {
continue
}

fieldsYmlPath = filepath.Join(modulesPath, module.Name(), s.Name(), "_meta", "fields.yml")
if _, err = os.Stat(fieldsYmlPath); !os.IsNotExist(err) {
files = append(files, &YmlFile{
Path: fieldsYmlPath,
Indent: indentByModule[modulesRoot],
})
} else if !os.IsNotExist(err) && err != nil {
return nil, err
}
}
return files, nil
}
22 changes: 12 additions & 10 deletions libbeat/scripts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,19 @@ coverage-report:
test ! -s ${COVERAGE_DIR}/unit.cov || go tool cover -html=${COVERAGE_DIR}/unit.cov -o ${COVERAGE_DIR}/unit.html


.PHONY: fields
fields:
echo $(PWD)
@go run ${ES_BEATS}/libbeat/scripts/cmd/global_fields/main.go --es_beats_path $(ES_BEATS) --beat_path $(PWD) $(FIELDS_FILE_PATH)


.PHONY: libbeat_fields
libbeat_fields:
@$(MAKE) -C ${ES_BEATS}/libbeat fields

.PHONY: update
update: ## @build Update expects the most recent version of libbeat in the GOPATH
update: python-env collect
update: python-env libbeat_fields collect
@echo "Updating generated files for ${BEAT_NAME}"

@# Update config files.
Expand All @@ -324,15 +334,7 @@ ifeq ($(BEAT_REF_YAML),true)
@chmod 0640 ${BEAT_NAME}.reference.yml
endif

@# Update libbeat fields.generated.yml
@$(MAKE) -C ${ES_BEATS}/libbeat fields

@# Update fields.yml
@test -s _meta/fields.generated.yml || cp _meta/fields.yml _meta/fields.generated.yml
ifeq ($(BEAT_NAME), libbeat)
@cp ${ES_BEATS}/libbeat/_meta/fields.generated.yml fields.yml
else
@cat ${ES_BEATS}/libbeat/_meta/fields.generated.yml _meta/fields.generated.yml > fields.yml
ifneq ($(BEAT_NAME), libbeat)
mkdir -p include
go run ${ES_BEATS}/dev-tools/cmd/asset/asset.go -pkg include fields.yml $(BEAT_NAME) > include/fields.go
endif
Expand Down
Loading