diff --git a/changelog/fragments/1681942680-fix-diag-zip-file.yaml b/changelog/fragments/1681942680-fix-diag-zip-file.yaml new file mode 100644 index 00000000000..e9ee76a2563 --- /dev/null +++ b/changelog/fragments/1681942680-fix-diag-zip-file.yaml @@ -0,0 +1,4 @@ +kind: bug-fix +summary: Fix diagnostic zip file handling of sub-directories in logs/. +component: diagnostics +pr: https://github.com/elastic/elastic-agent/pull/2523 diff --git a/internal/pkg/diagnostics/diagnostics.go b/internal/pkg/diagnostics/diagnostics.go index f3a3965daa4..7b3df7cfdd7 100644 --- a/internal/pkg/diagnostics/diagnostics.go +++ b/internal/pkg/diagnostics/diagnostics.go @@ -318,6 +318,15 @@ func zipLogsWithPath(pathsHome, commitName string, collectServices bool, zw *zip } } + _, err = zw.CreateHeader(&zip.FileHeader{ + Name: "logs/" + commitName + "/", + Method: zip.Deflate, + Modified: ts, + }) + if err != nil { + return err + } + // using Data() + "/logs", for some reason default paths/Logs() is the home dir... logPath := filepath.Join(pathsHome, "logs") + string(filepath.Separator) return filepath.WalkDir(logPath, func(path string, d fs.DirEntry, fErr error) error { @@ -339,7 +348,7 @@ func zipLogsWithPath(pathsHome, commitName string, collectServices bool, zw *zip if d.IsDir() { _, err := zw.CreateHeader(&zip.FileHeader{ - Name: "logs" + name + "/", + Name: "logs/" + filepath.ToSlash(name) + "/", Method: zip.Deflate, Modified: ts, }) @@ -407,7 +416,7 @@ func saveLogs(name string, logPath string, zw *zip.Writer) error { ts = li.ModTime() } zf, err := zw.CreateHeader(&zip.FileHeader{ - Name: "logs/" + name, + Name: "logs/" + filepath.ToSlash(name), Method: zip.Deflate, Modified: ts, }) diff --git a/internal/pkg/diagnostics/dianostics_test.go b/internal/pkg/diagnostics/dianostics_test.go new file mode 100644 index 00000000000..7cc2415ad82 --- /dev/null +++ b/internal/pkg/diagnostics/dianostics_test.go @@ -0,0 +1,57 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package diagnostics + +import ( + "archive/zip" + "bytes" + "os" + "path/filepath" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/elastic/elastic-agent/internal/pkg/agent/application/paths" +) + +func TestZipLogs(t *testing.T) { + // Setup a directory structure of: logs/httpjson/log.ndjson + { + paths.SetTop(t.TempDir()) + dir := filepath.Join(paths.Home(), "logs/sub-dir") + require.NoError(t, os.MkdirAll(dir, 0o700)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "log.ndjson"), []byte(".\n"), 0o600)) + } + + // Zip the logs directory. + buf := new(bytes.Buffer) + w := zip.NewWriter(buf) + require.NoError(t, zipLogs(w, time.Now())) + require.NoError(t, w.Close()) + + type zippedItem struct { + Name string + IsDir bool + } + + // Read back the contents. + r, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) + require.NoError(t, err) + var observed []zippedItem + for _, f := range r.File { + observed = append(observed, zippedItem{Name: f.Name, IsDir: f.FileInfo().IsDir()}) + } + + // Verify the results. + expected := []zippedItem{ + {"logs/", true}, + {"logs/elastic-agent-unknow/", true}, + {"logs/elastic-agent-unknow/sub-dir/", true}, + {"logs/elastic-agent-unknow/sub-dir/log.ndjson", false}, + } + assert.Equal(t, expected, observed) +}