Skip to content

Commit

Permalink
Merge branch 'main' into feat/drop-multierror
Browse files Browse the repository at this point in the history
  • Loading branch information
kruskall authored Jan 24, 2025
2 parents b06b8dc + 6be7c82 commit b90820c
Show file tree
Hide file tree
Showing 27 changed files with 824 additions and 23 deletions.
10 changes: 1 addition & 9 deletions .buildkite/hooks/pre-command
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

set -euo pipefail

# Secrets must be redacted
# https://buildkite.com/docs/pipelines/managing-log-output#redacted-environment-variables
PRIVATE_CI_GCS_CREDENTIALS_PATH="kv/ci-shared/platform-ingest/gcp-platform-ingest-ci-service-account"

if [[ "${BUILDKITE_LABEL:-}" == *"Pipeline upload"* || "${BUILDKITE_LABEL:-}" == *"Upload Pipeline"* ]]; then

Expand All @@ -13,11 +10,6 @@ if [[ "${BUILDKITE_LABEL:-}" == *"Pipeline upload"* || "${BUILDKITE_LABEL:-}" ==
fi
fi

if [[ "$BUILDKITE_PIPELINE_SLUG" == "beats-xpack-packetbeat" && "$BUILDKITE_STEP_KEY" == *"system-tests"* ]]; then
PRIVATE_CI_GCS_CREDENTIALS_SECRET=$(retry -t 5 -- vault kv get -field plaintext -format=json ${PRIVATE_CI_GCS_CREDENTIALS_PATH})
export PRIVATE_CI_GCS_CREDENTIALS_SECRET
fi

if [[ "$BUILDKITE_PIPELINE_SLUG" == "auditbeat" || \
"$BUILDKITE_PIPELINE_SLUG" == "beats-libbeat" || \
"$BUILDKITE_PIPELINE_SLUG" == "beats-macos-tests" || \
Expand Down Expand Up @@ -55,4 +47,4 @@ elif [[ "${CPU_ARCH}" == "aarch64" || "${CPU_ARCH}" == "arm64" ]]; then
else
echo "Unsupported OS"
exit 1
fi
fi
2 changes: 1 addition & 1 deletion .buildkite/pull-requests.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"always_trigger_comment_regex": "^/(?:test)",
"skip_ci_labels": ["skip-ci"],
"skip_target_branches": [ ],
"skip_ci_on_only_changed": [ ],
"skip_ci_on_only_changed": [ "^.github/", "^.pre-commit-config.yaml", "^.mergify.yml", "\\.md$", "^docs/", "^updatecli-compose.yaml"],
"always_require_ci_on_changed": [ ]
}
]
Expand Down
14 changes: 14 additions & 0 deletions .buildkite/scripts/gcp_auth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash

set -euo pipefail

echo "~~~ Authenticating GCP"
# Secrets must be redacted
# https://buildkite.com/docs/pipelines/managing-log-output#redacted-environment-variables
PRIVATE_CI_GCS_CREDENTIALS_PATH="kv/ci-shared/platform-ingest/gcp-platform-ingest-ci-service-account"
PRIVATE_CI_GCS_CREDENTIALS_SECRET=$(vault kv get -field plaintext -format=json ${PRIVATE_CI_GCS_CREDENTIALS_PATH})
export PRIVATE_CI_GCS_CREDENTIALS_SECRET
echo "${PRIVATE_CI_GCS_CREDENTIALS_SECRET}" > ./gcp.json
GOOGLE_APPLICATION_CREDENTIALS=$(realpath ./gcp.json)
export GOOGLE_APPLICATION_CREDENTIALS
gcloud auth activate-service-account --key-file="${GOOGLE_APPLICATION_CREDENTIALS}"
2 changes: 2 additions & 0 deletions .buildkite/x-pack/pipeline.xpack.packetbeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ steps:
key: "mandatory-win-2022-system-tests"
skip: "skipping due to elastic/beats#38142"
command: |
source .buildkite/scripts/gcp_auth.sh
Set-Location -Path x-pack/packetbeat
mage systemTest
retry:
Expand Down Expand Up @@ -323,6 +324,7 @@ steps:
key: "extended-win-10-system-tests"
skip: "skipping due to elastic/beats#38142"
command: |
source .buildkite/scripts/gcp_auth.sh
Set-Location -Path x-pack/packetbeat
mage systemTest
retry:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
- Prevent panic if libbeat processors are loaded more than once. {issue}41475[41475] {pull}41857[51857]
- Allow network condition to handle field values that are arrays of IP addresses. {pull}41918[41918]
- Fix a bug where log files are rotated on startup when interval is configured and rotateonstartup is disabled {issue}41894[41894] {pull}41895[41895]
- Fix setting unique registry for non beat receivers {issue}42288[42288] {pull}42292[42292]
- The Kafka output now drops events when there is an authorisation error {issue}42343[42343] {pull}42401[42401]

*Auditbeat*

Expand Down Expand Up @@ -376,6 +378,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
- Add ability to remove request trace logs from entityanalytics input. {pull}40004[40004]
- Refactor & cleanup with updates to default values and documentation. {pull}41834[41834]
- Update CEL mito extensions to v1.16.0. {pull}41727[41727]
- Filebeat's registry is now added to the Elastic-Agent diagnostics bundle {issue}33238[33238] {pull}41795[41795]
- Add `unifiedlogs` input for MacOS. {pull}41791[41791]
- Add evaluation state dump debugging option to CEL input. {pull}41335[41335]
- Added support for retry configuration in GCS input. {issue}11580[11580] {pull}41862[41862]
Expand Down
217 changes: 217 additions & 0 deletions filebeat/beater/diagnostics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 beater

import (
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/elastic/elastic-agent-libs/logp"
"github.com/elastic/elastic-agent-libs/paths"
)

func getRegexpsForRegistryFiles() ([]*regexp.Regexp, error) {
// We use regexps here because globs do not support specifying a character
// range like we do in the checkpoint file.

registryFileRegExps := []*regexp.Regexp{}
preFilesList := [][]string{
[]string{"^registry$"},
[]string{"^registry", "filebeat$"},
[]string{"^registry", "filebeat", "meta\\.json$"},
[]string{"^registry", "filebeat", "log\\.json$"},
[]string{"^registry", "filebeat", "active\\.dat$"},
[]string{"^registry", "filebeat", "[[:digit:]]*\\.json$"},
}

for _, lst := range preFilesList {
var path string
if filepath.Separator == '\\' {
path = strings.Join(lst, `\\`)
} else {
path = filepath.Join(lst...)
}

// Compile the reg exp, if there is an error, stop and return.
// There should be no error here as this code is tested in all
// supported OSes, however to avoid a code path that leads to a
// panic, we cannot use `regexp.MustCompile` and handle the error
re, err := regexp.Compile(path)
if err != nil {
return nil, fmt.Errorf("cannot compile reg exp: %w", err)
}

registryFileRegExps = append(registryFileRegExps, re)
}

return registryFileRegExps, nil
}

func gzipRegistry() []byte {
logger := logp.L().Named("diagnostics")
buf := bytes.Buffer{}
dataPath := paths.Resolve(paths.Data, "")
registryPath := filepath.Join(dataPath, "registry")
f, err := os.CreateTemp("", "filebeat-registry-*.tar")
if err != nil {
logger.Errorw("cannot create temporary registry archive", "error.message", err)
}
// Close the file, we just need the empty file created to use it later
f.Close()
defer logger.Debug("finished gziping Filebeat's registry")

defer func() {
if err := os.Remove(f.Name()); err != nil {
logger.Warnf("cannot remove temporary registry archive '%s': '%s'", f.Name(), err)
}
}()

logger.Debugf("temporary file '%s' created", f.Name())
if err := tarFolder(logger, registryPath, f.Name()); err != nil {
logger.Errorw(fmt.Sprintf("cannot archive Filebeat's registry at '%s'", f.Name()), "error.message", err)
}

if err := gzipFile(logger, f.Name(), &buf); err != nil {
logger.Errorw("cannot gzip Filebeat's registry", "error.message", err)
}

// if the final file is too large, skip it
if buf.Len() >= 20_000_000 { // 20 Mb
logger.Warnf("registry is too large for diagnostics, %dmb bytes > 20mb", buf.Len()/1_000_000)
return nil
}

return buf.Bytes()
}

// gzipFile gzips src writing the compressed data to dst
func gzipFile(logger *logp.Logger, src string, dst io.Writer) error {
reader, err := os.Open(src)
if err != nil {
return fmt.Errorf("cannot open '%s': '%w'", src, err)
}
defer reader.Close()

writer := gzip.NewWriter(dst)
defer writer.Close()
writer.Name = filepath.Base(src)

if _, err := io.Copy(writer, reader); err != nil {
if err != nil {
return fmt.Errorf("cannot gzip file '%s': '%w'", src, err)
}
}

return nil
}

// tarFolder creates a tar archive from the folder src and stores it at dst.
//
// dst must be the full path with extension, e.g: /tmp/foo.tar
// If src is not a folder an error is retruned
func tarFolder(logger *logp.Logger, src, dst string) error {
fullPath, err := filepath.Abs(src)
if err != nil {
return fmt.Errorf("cannot get full path from '%s': '%w'", src, err)
}

tarFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("cannot create tar file '%s': '%w'", dst, err)
}
defer tarFile.Close()

tarWriter := tar.NewWriter(tarFile)
defer tarWriter.Close()

info, err := os.Stat(fullPath)
if err != nil {
return fmt.Errorf("cannot stat '%s': '%w'", fullPath, err)
}

if !info.IsDir() {
return fmt.Errorf("'%s' is not a directory", fullPath)
}
baseDir := filepath.Base(src)

logger.Debugf("starting to walk '%s'", fullPath)

// This error should never happen at runtime, if something
// breaks it should break the tests and be fixed before a
// release. We handle the error here to avoid a code path
// that can end into a panic.
registryFileRegExps, err := getRegexpsForRegistryFiles()
if err != nil {
return err
}

return filepath.Walk(fullPath, func(path string, info fs.FileInfo, prevErr error) error {
// Stop if there is any errors
if prevErr != nil {
return prevErr
}

pathInTar := filepath.Join(baseDir, strings.TrimPrefix(path, src))
if !matchRegistyFiles(registryFileRegExps, pathInTar) {
return nil
}
header, err := tar.FileInfoHeader(info, info.Name())
if err != nil {
return fmt.Errorf("cannot create tar info header: '%w'", err)
}
header.Name = pathInTar

if err := tarWriter.WriteHeader(header); err != nil {
return fmt.Errorf("cannot write tar header for '%s': '%w'", path, err)
}

if info.IsDir() {
return nil
}

file, err := os.Open(path)
if err != nil {
return fmt.Errorf("cannot open '%s' for reading: '%w", path, err)
}
defer file.Close()

logger.Debugf("adding '%s' to the tar archive", file.Name())
if _, err := io.Copy(tarWriter, file); err != nil {
return fmt.Errorf("cannot read '%s': '%w'", path, err)
}

return nil
})
}

func matchRegistyFiles(registryFileRegExps []*regexp.Regexp, path string) bool {
for _, regExp := range registryFileRegExps {
if regExp.MatchString(path) {
return true
}
}
return false
}
66 changes: 66 additions & 0 deletions filebeat/beater/diagnostics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 beater

import (
"fmt"
"path/filepath"
"testing"
)

func TestMatchRegistryFiles(t *testing.T) {
positiveMatches := []string{
filepath.Join("registry", "filebeat", "49855.json"),
filepath.Join("registry", "filebeat", "active.dat"),
filepath.Join("registry", "filebeat", "meta.json"),
filepath.Join("registry", "filebeat", "log.json"),
}
negativeMatches := []string{
filepath.Join("registry", "filebeat", "bar.dat"),
filepath.Join("registry", "filebeat", "log.txt"),
filepath.Join("registry", "42.json"),
filepath.Join("nop", "active.dat"),
}
registryFileRegExps, err := getRegexpsForRegistryFiles()
if err != nil {
t.Fatalf("cannot compile regexps for registry paths: %s", err)
}

testFn := func(t *testing.T, path string, match bool) {
result := matchRegistyFiles(registryFileRegExps, path)
if result != match {
t.Errorf(
"mathRegisryFiles('%s') should return %t, got %t instead",
path,
match,
result)
}
}

for _, path := range positiveMatches {
t.Run(fmt.Sprintf("%s returns true", path), func(t *testing.T) {
testFn(t, path, true)
})
}

for _, path := range negativeMatches {
t.Run(fmt.Sprintf("%s returns false", path), func(t *testing.T) {
testFn(t, path, false)
})
}
}
7 changes: 7 additions & 0 deletions filebeat/beater/filebeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ func newBeater(b *beat.Beat, plugins PluginFactory, rawConfig *conf.C) (beat.Bea
}
return data
})

b.Manager.RegisterDiagnosticHook(
"registry",
"Filebeat's registry",
"registry.tar.gz",
"application/octet-stream",
gzipRegistry)
}

// Add inputs created by the modules
Expand Down
2 changes: 2 additions & 0 deletions libbeat/cmd/instance/beat.go
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,8 @@ func (b *Beat) configure(settings Settings) error {
debug.SetGCPercent(gcPercent)
}

b.Info.Monitoring.Namespace = monitoring.GetNamespace("dataset")

b.Beat.BeatConfig, err = b.BeatConfig()
if err != nil {
return err
Expand Down
Loading

0 comments on commit b90820c

Please sign in to comment.