Skip to content

Commit f56d995

Browse files
committed
Stop following symlinks.
Previously symlinks were followed. This had the consequence if a symlink and the file itself existed, the file was read twice. Now symlinks are not followed anymore. This closes elastic#1686
1 parent c214109 commit f56d995

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

CHANGELOG.asciidoc

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ https://github.com/elastic/beats/compare/v5.0.0-alpha3...master[Check the HEAD d
2222

2323
*Filebeat*
2424

25+
- Stop following symlink. Symlinks are now ignored: {pull}1686[1686]
26+
2527
*Winlogbeat*
2628

2729

@@ -79,7 +81,7 @@ https://github.com/elastic/beats/compare/v5.0.0alpha2...v5.0.0-alpha3[View commi
7981
*Affecting all Beats*
8082
8183
- All configuration settings under `shipper:` are moved to be top level configuration settings. I.e.
82-
`shipper.name:` becomes `name:` in the configuration file. #1570
84+
`shipper.name:` becomes `name:` in the configuration file. {pull}1570[1570]
8385
8486
*Packetbeat*
8587

filebeat/crawler/prospector_log.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,15 @@ func (p *ProspectorLog) getFiles() map[string]os.FileInfo {
7979
}
8080

8181
// Stat the file, following any symlinks.
82-
fileinfo, err := os.Stat(file)
82+
fileinfo, err := os.Lstat(file)
8383
if err != nil {
8484
logp.Debug("prospector", "stat(%s) failed: %s", file, err)
8585
continue
8686
}
87+
if fileinfo.Mode()&os.ModeSymlink != 0 {
88+
logp.Debug("prospector", "File %s skipped as it is a symlink.", file)
89+
continue
90+
}
8791

8892
if fileinfo.IsDir() {
8993
logp.Debug("prospector", "Skipping directory: %s", file)

filebeat/tests/system/test_prospector.py

+38
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,41 @@ def test_close_older_file_rotation_and_removal(self):
514514
max_timeout=10)
515515

516516
filebeat.check_kill_and_wait()
517+
518+
def test_skip_symlinks(self):
519+
"""
520+
Test that symlinks are skipped
521+
"""
522+
self.render_config_template(
523+
path=os.path.abspath(self.working_dir) + "/log/*",
524+
)
525+
526+
os.mkdir(self.working_dir + "/log/")
527+
testfile = self.working_dir + "/log/test-2016.log"
528+
symlink_file = self.working_dir + "/log/test.log"
529+
530+
# write first line
531+
with open(testfile, 'a') as file:
532+
file.write("Hello world\n")
533+
534+
os.symlink(testfile, symlink_file)
535+
536+
filebeat = self.start_beat()
537+
538+
# wait for file to be skipped
539+
self.wait_until(
540+
lambda: self.log_contains("skipped as it is a symlink"),
541+
max_timeout=10)
542+
543+
# wait for log to be read
544+
self.wait_until(
545+
lambda: self.output_has(lines=1),
546+
max_timeout=15)
547+
548+
time.sleep(5)
549+
filebeat.check_kill_and_wait()
550+
551+
data = self.read_output()
552+
553+
# Make sure there is only one entry, means it didn't follow the symlink
554+
assert len(data) == 1

0 commit comments

Comments
 (0)