Skip to content

Conversation

alecholmes
Copy link
Contributor

@alecholmes alecholmes commented Aug 19, 2025

This is a prefactor that changes how locally cached fleet config files are deleted. A forthcoming PR will rely on this change to fix how configs are managed when reloading a new config fails.

For background, fleet config directories typically look like this when a new config is being reloaded:

drwx------ 2 alec alec  40 Aug 19 11:30 1755653410
-rw-r--r-- 1 alec alec 208 Aug 19 11:30 1755653410.conf
drwx------ 2 alec alec  40 Aug 19 11:38 1755653894
-rw-r--r-- 1 alec alec 208 Aug 19 11:38 1755653894.conf
-rw-r--r-- 1 alec alec 404 Aug 19 11:38 header.conf
lrwxrwxrwx 1 alec alec 106 Aug 19 11:38 new.conf -> /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755653894.conf
lrwxrwxrwx 1 alec alec 106 Aug 19 11:30 old.conf -> /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755653410.conf

When deleting the old config, the old logic would sort the directory contents and delete everything except the last N entries.

This PR changes deletion to be explicit. When deleting old.conf, the symlink is resolved and the related files and directories are deletes. In the example above, old.conf resolves to 1755653410.conf. This new code will delete all files/dirs that match the glob 1755653410* (1755653410.conf and the 1755653410 directory).


Enter [N/A] in the box, if an item is not applicable to your change.

Testing
Before we can approve your change; please submit the following in a comment:

  • Example configuration file for the change
  • Debug log output from testing the change (see comment)
  • Attached Valgrind output that shows no leaks or memory corruption was found (see comment)

If this is a change to packaging of containers or native binaries then please confirm it works for all targets.

  • Run local packaging test showing all targets (including any new ones) build.
  • Set ok-package-test label to test for all targets (requires maintainer to do).

Documentation

  • Documentation required for this feature

Backporting

  • Backport to latest stable release.

Fluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented timestamp truncation in generated config names.
    • Hardened symlink resolution for timestamped config paths.
    • Improved reload error handling and resource cleanup for greater stability.
    • Corrected timestamp logging to avoid formatting issues.
  • Refactor

    • Unified, symlink-aware deletion flow for config files/directories.
    • Old configuration is now fully removed before commit finalization.
    • Removed automatic “load newest” fallback; reload now considers only existing/current/new states.
    • Enhanced deletion and reload logs for clearer diagnostics.

Copy link

coderabbitai bot commented Aug 19, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The patch modifies in_calyptia_fleet.c to fix timestamp filename generation, harden symlink resolution, rework deletion via a generic symlink-aware API, adjust reload/error handling and resource management, remove “load newest” fallback, update timestamp/log formatting, and add recursive deletion with refined logging.

Changes

Cohort / File(s) Summary
Calyptia Fleet plugin core
plugins/in_calyptia_fleet/in_calyptia_fleet.c
- Fix snprintf usage for 32-byte timestamp strings
- Remove config pre-validation during reload
- Harden readlink handling and timestamped path parsing
- Tighten reload error paths and resource freeing
- Remove fallback to auto-load newest config
- Introduce symlink-aware calyptia_config_delete_by_symlink + helpers (wrappers for new/old, recursive delete_dir)
- Adjust commit flow to delete old files first
- Enhance deletion/log messages; use 64-bit timestamp formats

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Timer as Collector/Timer
  participant Fleet as in_calyptia_fleet
  participant FB as Fluent Bit Core
  participant FS as Filesystem

  rect rgba(217,237,247,0.5)
  note right of Fleet: Reload flow (updated)
  Timer->>Fleet: Trigger reload attempt
  Fleet->>FS: Resolve cfg symlink (readlink, parse timestamp)
  alt New config exists
    Fleet->>FB: Create reload context
    alt Context alloc OK
      FB-->>Fleet: Context ready
      Fleet->>FB: Apply new config
      alt Apply fails
        Fleet->>Fleet: Free reload context, resume collectors
        Fleet->>FS: Cleanup allocated paths
        Fleet-->>Timer: Return gracefully
      else Apply succeeds
        Fleet->>FS: Commit new config (delete old first)
        Fleet-->>Timer: Reload complete
      end
    else Context alloc fails
      Fleet->>Fleet: Resume collectors, free cfgpath/reload
      Fleet-->>Timer: Return
    end
  else No new config
    Fleet-->>Timer: No-op (no “load newest” fallback)
  end
  end
Loading
sequenceDiagram
  autonumber
  participant Fleet as in_calyptia_fleet
  participant FS as Filesystem
  participant Glob as Glob Matcher

  rect rgba(223,240,216,0.5)
  note right of Fleet: Symlink-aware deletion (new)
  Fleet->>FS: readlink(symlink) -> real target
  Fleet->>Fleet: Derive glob prefix (replace ext with '*')
  Fleet->>Glob: Match files/dirs by prefix
  loop For each match
    alt Directory
      Fleet->>FS: delete_dir(path) (recursive)
    else File
      Fleet->>FS: unlink(path)
    end
  end
  Fleet->>FS: unlink(symlink)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • koleini
  • fujimotos
  • edsiper

Poem

A nibble of code, a hop through the night,
I tidied the links and set reloads right.
Old twigs swept clean, new burrows in place,
Timestamps aligned in a neatly-formatted trace.
With whiskers a-twitch, I prune and I preen—
Fleet runs smooth, swift, and serene. 🐇✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@alecholmes
Copy link
Contributor Author

Process output exercising the changed code path. Issues reported by valgrind existed prior to this PR.

==259283== Memcheck, a memory error detector
==259283== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==259283== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==259283== Command: /home/alec/dev/fluent-bit/build/bin/fluent-bit --config local.yaml
==259283==
Fluent Bit v4.1.0
* Copyright (C) 2015-2025 The Fluent Bit Authors
* Fluent Bit is a CNCF sub-project under the umbrella of Fluentd
* https://fluentbit.io

______ _                  _    ______ _ _             ___  _____
|  ___| |                | |   | ___ (_) |           /   ||  _  |
| |_  | |_   _  ___ _ __ | |_  | |_/ /_| |_  __   __/ /| || |/' |
|  _| | | | | |/ _ \ '_ \| __| | ___ \ | __| \ \ / / /_| ||  /| |
| |   | | |_| |  __/ | | | |_  | |_/ / | |_   \ V /\___  |\ |_/ /
\_|   |_|\__,_|\___|_| |_|\__| \____/|_|\__|   \_/     |_(_)___/


[2025/08/19 11:45:43.651242991] [ info] [fluent bit] version=4.1.0, commit=945d81a9ec, pid=259283
[2025/08/19 11:45:43.687015943] [ info] [custom:calyptia:calyptia.0] read UUID (1f6e3744-1b0c-4004-a726-f981e0159e16) from file: /tmp/calyptia-fleet/machine-id.conf
[2025/08/19 11:45:43.841439313] [ info] [custom:calyptia:calyptia.0] custom initialized!
[2025/08/19 11:45:43.846492647] [ info] [storage] ver=1.5.3, type=memory, sync=normal, checksum=off, max_chunks_up=128
[2025/08/19 11:45:43.847179552] [ info] [simd    ] disabled
[2025/08/19 11:45:43.847585295] [ info] [cmetrics] version=1.0.5
[2025/08/19 11:45:43.847980372] [ info] [ctraces ] version=0.6.6
[2025/08/19 11:45:43.860566081] [ info] [input:fluentbit_metrics:fluentbit_metrics.0] initializing
[2025/08/19 11:45:43.861533149] [ info] [input:fluentbit_metrics:fluentbit_metrics.0] storage_strategy='memory' (memory only)
[2025/08/19 11:45:43.998926300] [ info] [input:calyptia_fleet:calyptia_fleet.1] initializing
[2025/08/19 11:45:43.999149088] [ info] [input:calyptia_fleet:calyptia_fleet.1] storage_strategy='memory' (memory only)
[2025/08/19 11:45:44.169863] [ info] [input:calyptia_fleet:calyptia_fleet.1] initializing calyptia fleet input.
[2025/08/19 11:45:44.21319722] [ info] [input:calyptia_fleet:calyptia_fleet.1] loading configuration from /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/cur.conf.
[2025/08/19 11:45:44.22747574] [ info] [input:calyptia_fleet:calyptia_fleet.1] changing to config dir: /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755653894
[2025/08/19 11:45:44.61933803] [ info] [sp] stream processor started
[2025/08/19 11:45:44.65280956] [ info] [engine] Shutdown Grace Period=5, Shutdown Input Grace Period=2
[2025/08/19 11:45:49] [engine] caught signal (SIGHUP)
[2025/08/19 11:45:49.77082063] [ info] reloading instance pid=259283 tid=0x4852020
[2025/08/19 11:45:49.104875354] [ info] [reload] stop everything of the old context
[2025/08/19 11:45:49.115146352] [ warn] [engine] service will shutdown when all remaining tasks are flushed
[2025/08/19 11:45:49.116346623] [ info] [input] pausing fluentbit_metrics.0
[2025/08/19 11:45:49.117524146] [ info] [input] pausing calyptia_fleet.1
[2025/08/19 11:45:49.847853019] [ info] [engine] service has stopped (0 pending tasks)
[2025/08/19 11:45:49.848194306] [ info] [input] pausing fluentbit_metrics.0
[2025/08/19 11:45:49.848363178] [ info] [input] pausing calyptia_fleet.1
[2025/08/19 11:45:49.902349371] [ info] [reload] start everything
[2025/08/19 11:45:49.904470794] [ info] [fluent bit] version=4.1.0, commit=945d81a9ec, pid=259283
[2025/08/19 11:45:49.905380029] [ info] [custom:calyptia:calyptia.0] read UUID (1f6e3744-1b0c-4004-a726-f981e0159e16) from file: /tmp/calyptia-fleet/machine-id.conf
[2025/08/19 11:45:49.914055553] [ info] [custom:calyptia:calyptia.0] custom initialized!
[2025/08/19 11:45:49.914429338] [ info] [storage] ver=1.5.3, type=memory, sync=normal, checksum=off, max_chunks_up=128
[2025/08/19 11:45:49.914564461] [ info] [simd    ] disabled
[2025/08/19 11:45:49.914651168] [ info] [cmetrics] version=1.0.5
[2025/08/19 11:45:49.914735500] [ info] [ctraces ] version=0.6.6
[2025/08/19 11:45:49.916084811] [ info] [input:dummy:dummy.0] initializing
[2025/08/19 11:45:49.916344598] [ info] [input:dummy:dummy.0] storage_strategy='memory' (memory only)
[2025/08/19 11:45:49.927721244] [ info] [input:fluentbit_metrics:fluentbit_metrics.1] initializing
[2025/08/19 11:45:49.927855700] [ info] [input:fluentbit_metrics:fluentbit_metrics.1] storage_strategy='memory' (memory only)
[2025/08/19 11:45:49.940503283] [ info] [input:calyptia_fleet:calyptia_fleet.2] initializing
[2025/08/19 11:45:49.940668531] [ info] [input:calyptia_fleet:calyptia_fleet.2] storage_strategy='memory' (memory only)
[2025/08/19 11:45:49.940921526] [ info] [input:calyptia_fleet:calyptia_fleet.2] initializing calyptia fleet input.
[2025/08/19 11:45:49.944360845] [ info] [input:calyptia_fleet:calyptia_fleet.2] fleet collector initialized with interval: 5 sec 0 nsec
[2025/08/19 11:45:49.966884848] [ info] [output:stdout:stdout.0] worker #0 started
[2025/08/19 11:45:51.379111436] [ info] [output:calyptia:calyptia.1] connected to Calyptia, agent_id='a08a6ccc-d058-421a-87b7-16ac2380cde2'
[2025/08/19 11:45:51.391208653] [ info] [output:calyptia:calyptia.1] agent registration successful
[2025/08/19 11:45:51.392906084] [ info] [sp] stream processor started
[2025/08/19 11:45:51.396436400] [ info] [engine] Shutdown Grace Period=5, Shutdown Input Grace Period=2
[0] dummy.0: [[1755629151.848250367, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629152.862796262, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629153.847197321, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629154.845176573, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629156.066686889, {}], {"message"=>"dummy-v3"}]
==259283== Thread 2 flb-pipeline:
==259283== Conditional jump or move depends on uninitialised value(s)
==259283==    at 0x281B08: output_pre_cb_flush (flb_output.h:690)
==259283==    by 0x1534B6B: co_switch (aarch64.c:133)
==259283==    by 0xFFFFFFFFFFFFFFFF: ???
==259283==  Uninitialised value was created by a heap allocation
==259283==    at 0x4865058: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-arm64-linux.so)
==259283==    by 0x2C75EF: flb_malloc (flb_mem.h:80)
==259283==    by 0x2C8603: flb_task_create (flb_task.c:422)
==259283==    by 0x2C310B: flb_engine_dispatch (flb_engine_dispatch.c:311)
==259283==    by 0x2BAF7F: flb_engine_flush (flb_engine.c:175)
==259283==    by 0x2BCA67: flb_engine_handle_event (flb_engine.c:580)
==259283==    by 0x2BCA67: flb_engine_start (flb_engine.c:1003)
==259283==    by 0x239973: flb_lib_worker (flb_lib.c:835)
==259283==    by 0x50DD5B7: start_thread (pthread_create.c:442)
==259283==    by 0x5145EDB: thread_start (clone.S:79)
==259283==
[0] dummy.0: [[1755629156.850109263, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629157.846990658, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629158.844911744, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629159.846613851, {}], {"message"=>"dummy-v3"}]
[2025/08/19 11:46:01.68406037] [ info] [input:calyptia_fleet:calyptia_fleet.2] creating config file with timestamp 1755654357
[2025/08/19 11:46:01.70326922] [ info] [input:calyptia_fleet:calyptia_fleet.2] fleet API returned config with newer timestamp than current config (1755653894 -> 1755654357)
[2025/08/19 11:46:01.305608876] [ info] [input:calyptia_fleet:calyptia_fleet.2] loading configuration from /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/new.conf.
[2025/08/19 11:46:01.305954579] [ info] [input:calyptia_fleet:calyptia_fleet.2] changing to config dir: /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755654357
[0] dummy.0: [[1755629160.857584681, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629161.846776119, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629162.846304179, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629163.844793506, {}], {"message"=>"dummy-v3"}]
[0] dummy.0: [[1755629164.844811932, {}], {"message"=>"dummy-v3"}]
[2025/08/19 11:46:06] [engine] caught signal (SIGHUP)
[2025/08/19 11:46:06.416902509] [ info] reloading instance pid=259283 tid=0x4852020
[2025/08/19 11:46:06.441729850] [ info] [reload] stop everything of the old context
[2025/08/19 11:46:06.442243133] [ warn] [engine] service will shutdown when all remaining tasks are flushed
[2025/08/19 11:46:06.443689651] [ info] [input] pausing dummy.0
[2025/08/19 11:46:06.444132310] [ info] [input] pausing fluentbit_metrics.1
[0] dummy.0: [[1755629165.857967184, {}], {"message"=>"dummy-v3"}]
[2025/08/19 11:46:06.444504596] [ info] [input] pausing calyptia_fleet.2
[2025/08/19 11:46:06.846768129] [ info] [engine] service has stopped (0 pending tasks)
[2025/08/19 11:46:06.847230413] [ info] [input] pausing dummy.0
[2025/08/19 11:46:06.847734571] [ info] [input] pausing fluentbit_metrics.1
[2025/08/19 11:46:06.848092982] [ info] [input] pausing calyptia_fleet.2
[2025/08/19 11:46:06.850355486] [ info] [output:stdout:stdout.0] thread worker #0 stopping...
[2025/08/19 11:46:06.852822987] [ info] [output:stdout:stdout.0] thread worker #0 stopped
[2025/08/19 11:46:06.868854931] [ info] [reload] start everything
[2025/08/19 11:46:06.870140660] [ info] [fluent bit] version=4.1.0, commit=945d81a9ec, pid=259283
[2025/08/19 11:46:06.871104228] [ info] [custom:calyptia:calyptia.0] read UUID (1f6e3744-1b0c-4004-a726-f981e0159e16) from file: /tmp/calyptia-fleet/machine-id.conf
[2025/08/19 11:46:06.874680502] [ info] [custom:calyptia:calyptia.0] custom initialized!
[2025/08/19 11:46:06.874893540] [ info] [storage] ver=1.5.3, type=memory, sync=normal, checksum=off, max_chunks_up=128
[2025/08/19 11:46:06.875024038] [ info] [simd    ] disabled
[2025/08/19 11:46:06.875115162] [ info] [cmetrics] version=1.0.5
[2025/08/19 11:46:06.875326325] [ info] [ctraces ] version=0.6.6
[2025/08/19 11:46:06.876774093] [ info] [input:dummy:dummy.0] initializing
[2025/08/19 11:46:06.876916673] [ info] [input:dummy:dummy.0] storage_strategy='memory' (memory only)
[2025/08/19 11:46:06.878372149] [ info] [input:fluentbit_metrics:fluentbit_metrics.1] initializing
[2025/08/19 11:46:06.878503606] [ info] [input:fluentbit_metrics:fluentbit_metrics.1] storage_strategy='memory' (memory only)
[2025/08/19 11:46:06.892087757] [ info] [input:calyptia_fleet:calyptia_fleet.2] initializing
[2025/08/19 11:46:06.892277129] [ info] [input:calyptia_fleet:calyptia_fleet.2] storage_strategy='memory' (memory only)
[2025/08/19 11:46:06.892431501] [ info] [input:calyptia_fleet:calyptia_fleet.2] initializing calyptia fleet input.
[2025/08/19 11:46:06.895423618] [ info] [input:calyptia_fleet:calyptia_fleet.2] deleting config directory: /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755653894
[2025/08/19 11:46:06.896709597] [ warn] [read_glob] glob: [/tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755653894/*] no match
[2025/08/19 11:46:06.897767871] [ info] [input:calyptia_fleet:calyptia_fleet.2] deleting config file: /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/1755653894.conf
[2025/08/19 11:46:06.898654648] [ info] [input:calyptia_fleet:calyptia_fleet.2] deleting config symlink: /tmp/calyptia-fleet/cc4bfa21970aaf16c4739274d32e47a6a0829590edf4fa95f06232a98d72693b/hello/old.conf
[2025/08/19 11:46:06.899536634] [ info] [input:calyptia_fleet:calyptia_fleet.2] fleet collector initialized with interval: 5 sec 0 nsec
[2025/08/19 11:46:06.916316232] [ info] [output:stdout:stdout.0] worker #0 started
[2025/08/19 11:46:16.926347378] [error] [net] connection #41 timeout after 10 seconds to: cloud-api.calyptia.com:443
[2025/08/19 11:46:16.929649824] [ warn] [output:calyptia:calyptia.1] agent registration failed
[2025/08/19 11:46:16.930261897] [ info] [sp] stream processor started
[2025/08/19 11:46:16.930535017] [ info] [engine] Shutdown Grace Period=5, Shutdown Input Grace Period=2
[0] dummy.0: [[1755629177.845773259, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629178.877889948, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629179.855929862, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629180.846755523, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629181.863098972, {}], {"message"=>"dummy-v4"}]
[2025/08/19 11:46:22.848338018] [ info] [output:calyptia:calyptia.1] missing agent_id or agent_token, attempting re-registration register_retry_on_flush=true
[2025/08/19 11:46:23.155039419] [ info] [output:calyptia:calyptia.1] connected to Calyptia, agent_id='a08a6ccc-d058-421a-87b7-16ac2380cde2'
[2025/08/19 11:46:23.156550019] [ info] [output:calyptia:calyptia.1] agent registration successful
[0] dummy.0: [[1755629182.846429716, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629183.846601223, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629184.852809048, {}], {"message"=>"dummy-v4"}]
[0] dummy.0: [[1755629185.848539212, {}], {"message"=>"dummy-v4"}]
^C[2025/08/19 11:46:27] [engine] caught signal (SIGINT)
[2025/08/19 11:46:27.557494323] [ warn] [engine] service will shutdown in max 5 seconds
[2025/08/19 11:46:27.557739653] [ info] [input] pausing dummy.0
[2025/08/19 11:46:27.557877692] [ info] [input] pausing fluentbit_metrics.1
[2025/08/19 11:46:27.557995773] [ info] [input] pausing calyptia_fleet.2
[0] dummy.0: [[1755629186.847405116, {}], {"message"=>"dummy-v4"}]
[2025/08/19 11:46:27.845340827] [ info] [engine] service has stopped (0 pending tasks)
[2025/08/19 11:46:27.845964775] [ info] [input] pausing dummy.0
[2025/08/19 11:46:27.846487891] [ info] [input] pausing fluentbit_metrics.1
[2025/08/19 11:46:27.846948300] [ info] [input] pausing calyptia_fleet.2
[2025/08/19 11:46:27.847754995] [ info] [output:stdout:stdout.0] thread worker #0 stopping...
[2025/08/19 11:46:27.848485900] [ info] [output:stdout:stdout.0] thread worker #0 stopped
==259283==
==259283== HEAP SUMMARY:
==259283==     in use at exit: 201,393 bytes in 6 blocks
==259283==   total heap usage: 59,013 allocs, 59,007 frees, 25,412,237 bytes allocated
==259283==
==259283== Thread 1:
==259283== 201,393 (64 direct, 201,329 indirect) bytes in 1 blocks are definitely lost in loss record 6 of 6
==259283==    at 0x4869F34: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-arm64-linux.so)
==259283==    by 0x25E70F: flb_calloc (flb_mem.h:95)
==259283==    by 0x2674F7: flb_input_coro_create (flb_input.h:524)
==259283==    by 0x2674F7: flb_input_coro_collect (flb_input.h:627)
==259283==    by 0x2674F7: flb_input_collector_fd (flb_input.c:2177)
==259283==    by 0x2BCAEF: flb_engine_handle_event (flb_engine.c:595)
==259283==    by 0x2BCAEF: flb_engine_start (flb_engine.c:1003)
==259283==    by 0x239973: flb_lib_worker (flb_lib.c:835)
==259283==    by 0x50DD5B7: start_thread (pthread_create.c:442)
==259283==    by 0x5145EDB: thread_start (clone.S:79)
==259283==
==259283== LEAK SUMMARY:
==259283==    definitely lost: 64 bytes in 1 blocks
==259283==    indirectly lost: 201,329 bytes in 5 blocks
==259283==      possibly lost: 0 bytes in 0 blocks
==259283==    still reachable: 0 bytes in 0 blocks
==259283==         suppressed: 0 bytes in 0 blocks
==259283==
==259283== For lists of detected and suppressed errors, rerun with: -s
==259283== ERROR SUMMARY: 3 errors from 2 contexts (suppressed: 0 from 0)

char s_last_modified[32];

snprintf(s_last_modified, sizeof(s_last_modified)-1, "%d", (int)t);
snprintf(s_last_modified, sizeof(s_last_modified), "%d", (int)t);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

snprintf will properly null-terminate.

static int test_config_is_valid(struct flb_in_calyptia_fleet_config *ctx,
flb_sds_t cfgpath)
{
return FLB_TRUE;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

test_config_is_valid is a no-op in practice and according to @pwhelan we'll never be ably to fully validate up front. Removing this function.

}

static int calyptia_config_delete_old_dir(const char *cfgpath)
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I deleted a couple of funcs and replaced them new ones. The diff doesn't display well since the old and new code is vaguely similar.

else if (exists_new_fleet_config(ctx) == FLB_TRUE) {
return execute_reload(ctx, new_fleet_config_filename(ctx));
}
else {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The branches above will load either current or new config. No need to pick otherwise random config and a subsequent PR will refactor this function a bit anyway.

@alecholmes
Copy link
Contributor Author

@coderabbitai review

Copy link

coderabbitai bot commented Aug 19, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
plugins/in_calyptia_fleet/in_calyptia_fleet.c (3)

602-606: Destroy pthread attributes after use

You initialize a detached attribute, but never destroy it. Add pthread_attr_destroy to avoid leaking resources on some libpthread implementations.

Apply this diff:

     pthread_attr_init(&ptha);
     pthread_attr_setdetachstate(&ptha, PTHREAD_CREATE_DETACHED);
     pthread_create(&pth, &ptha, do_reload, reload);
+    pthread_attr_destroy(&ptha);

1301-1316: Index type nit: prefer size_t for array iteration

files->entry_count is a size_t. Using int and casting each iteration is unnecessary and could overflow in extreme cases.

Apply this diff:

-    int idx;
+    size_t idx;
...
-    for (idx = 0; idx < ((ssize_t)files->entry_count); idx++) {
+    for (idx = 0; idx < files->entry_count; idx++) {

1501-1503: Avoid redundant unlink after calyptia_config_delete_old()

c alyptia_config_delete_old() already unlinks the old symlink. The extra unlink likely hits ENOENT and is redundant.

Apply this diff:

-    if (exists_old_fleet_config(ctx) == FLB_TRUE) {
-        calyptia_config_delete_old(ctx);
-        unlink(cfgoldname);
-    }
+    if (exists_old_fleet_config(ctx) == FLB_TRUE) {
+        (void) calyptia_config_delete_old(ctx);
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 945d81a and 2fbb73c.

📒 Files selected for processing (1)
  • plugins/in_calyptia_fleet/in_calyptia_fleet.c (7 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: PR - fuzzing test
🔇 Additional comments (3)
plugins/in_calyptia_fleet/in_calyptia_fleet.c (3)

506-511: Good hardening of readlink usage and NUL-termination

Bounds checking and explicit termination eliminate common pitfalls here. Looks solid.


569-572: Nice: added allocation failure handling and cleanup on error path

Freeing cfgpath and reload on failure avoids leaks and inconsistent state. Good catch.

Also applies to: 586-586


987-988: Correct 64-bit logging for timestamps

Switching to %lld prevents truncation when printing 64-bit time values. Good.

Comment on lines 235 to 236
snprintf(s_last_modified, sizeof(s_last_modified), "%d", (int)t);
return fleet_config_filename(ctx, s_last_modified);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix narrowing conversion of time_t to int when formatting timestamp

On many platforms time_t is 64-bit. Casting to int truncates and can generate wrong filenames, breaking symlink targets and cleanup. Format as 64-bit.

Apply this diff:

-    snprintf(s_last_modified, sizeof(s_last_modified), "%d", (int)t);
+    snprintf(s_last_modified, sizeof(s_last_modified), "%lld", (long long) t);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
snprintf(s_last_modified, sizeof(s_last_modified), "%d", (int)t);
return fleet_config_filename(ctx, s_last_modified);
snprintf(s_last_modified, sizeof(s_last_modified), "%lld", (long long) t);
return fleet_config_filename(ctx, s_last_modified);
🤖 Prompt for AI Agents
In plugins/in_calyptia_fleet/in_calyptia_fleet.c around lines 235-236, the code
narrows time_t to int when building the timestamp string; replace the
cast/format with a 64-bit-safe approach: include <inttypes.h> (if not already
included), convert time_t to int64_t (e.g. int64_t ts = (int64_t)t;) and use
snprintf with a PRI macro (snprintf(s_last_modified, sizeof(s_last_modified),
"%" PRId64, ts);) so timestamps aren’t truncated on 64-bit time_t platforms.

Comment on lines 1331 to 1402
static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
{
struct cfl_array *confs;
struct cfl_array *tconfs;
flb_sds_t glob_files = NULL;
flb_sds_t config_path;
char realname[CALYPTIA_MAX_DIR_SIZE] = {0};
ssize_t len;
char *ext;
int idx;
struct stat entry_stat;
const char *entry_path;

if (ctx == NULL) {
return -1;
}

if (generate_base_fleet_directory(ctx, &glob_files) == NULL) {
flb_sds_destroy(glob_files);
return -1;
return FLB_FALSE;
}

if (ctx->fleet_config_legacy_format) {
if (flb_sds_cat_safe(&glob_files, PATH_SEPARATOR "*.conf", strlen(PATH_SEPARATOR "*.conf")) != 0) {
flb_sds_destroy(glob_files);
return -1;
}
} else if (flb_sds_cat_safe(&glob_files, PATH_SEPARATOR "*.yaml", strlen(PATH_SEPARATOR "*.yaml")) != 0) {
flb_sds_destroy(glob_files);
return -1;
/* Get the symlink path and extract prefix from its target */
config_path = config_filename_func(ctx);
if (config_path == NULL) {
flb_plg_error(ctx->ins, "error getting config path");
return FLB_FALSE;
}

confs = read_glob(glob_files);
if (confs == NULL) {
flb_sds_destroy(glob_files);
return -1;
/* Follow the symlink to get the target filename */
len = readlink(config_path, realname, sizeof(realname) - 1);
if (len < 0 || len >= (sizeof(realname) - 1)) {
flb_plg_error(ctx->ins, "error resolving symlink: %s", config_path);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
realname[len] = '\0';

tconfs = cfl_array_create(1);
if (tconfs == NULL) {
flb_sds_destroy(glob_files);
cfl_array_destroy(confs);
return -1;
/* Replace the extension with a glob (e.g. "/a/b.yaml" -> "/a/b*") */
ext = strrchr(realname, '.');
if (ext == NULL) {
flb_plg_error(ctx->ins, "symlink target has no extension: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
strcpy(ext, "*");

if (cfl_array_resizable(tconfs, FLB_TRUE) != 0) {
flb_sds_destroy(glob_files);
cfl_array_destroy(confs);
return -1;
/* Delete all files and directories that match the prefix pattern */
confs = read_glob(realname);
if (confs == NULL) {
flb_plg_warn(ctx->ins, "config glob did not return any files: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}

for (idx = 0; idx < confs->entry_count; idx++) {
if (fleet_config_path_timestamp(ctx, confs->entries[idx]->data.as_string) > 0) {
cfl_array_append_string(tconfs, confs->entries[idx]->data.as_string);
entry_path = confs->entries[idx]->data.as_string;
if (stat(entry_path, &entry_stat) == 0) {
if (S_ISDIR(entry_stat.st_mode)) {
flb_plg_info(ctx->ins, "deleting config directory: %s", entry_path);
if (delete_dir(entry_path) == FLB_FALSE) {
flb_plg_warn(ctx->ins, "unable to delete config directory: %s", entry_path);
}
} else {
flb_plg_info(ctx->ins, "deleting config file: %s", entry_path);
if (unlink(entry_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config file: %s", entry_path);
}
}
}
}

qsort(tconfs->entries, tconfs->entry_count,
sizeof(struct cfl_variant *),
cfl_array_qsort_conf_files);

for (idx = 0; idx < (((ssize_t)tconfs->entry_count) -3); idx++) {
unlink(tconfs->entries[idx]->data.as_string);
calyptia_config_delete_old_dir(tconfs->entries[idx]->data.as_string);
flb_plg_info(ctx->ins, "deleting config symlink: %s", config_path);
if (unlink(config_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config symlink: %s", config_path);
}

cfl_array_destroy(confs);
cfl_array_destroy(tconfs);
flb_sds_destroy(glob_files);

return 0;
flb_sds_destroy(config_path);
return FLB_TRUE;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Windows build will fail: readlink is used without platform guards

This function unconditionally calls readlink, but on Windows readlink is unavailable. Additionally, Windows code paths in this file still call calyptia_config_delete_old(), which wraps this function, so it must compile on Windows.

Wrap the POSIX implementation in a compile guard, and provide a minimal Windows fallback that removes the symlink path best-effort:

- static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
-                                              flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
-{
+ #ifndef FLB_SYSTEM_WINDOWS
+ static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
+                                              flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
+{
@@
-    len = readlink(config_path, realname, sizeof(realname) - 1);
+    len = readlink(config_path, realname, sizeof(realname) - 1);
@@
-    cfl_array_destroy(confs);
-    flb_sds_destroy(config_path);
-    return FLB_TRUE;
-}
+    cfl_array_destroy(confs);
+    flb_sds_destroy(config_path);
+    return FLB_TRUE;
+}
+ #else
+ static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
+                                              flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
+{
+    flb_sds_t config_path;
+    if (ctx == NULL) {
+        return FLB_FALSE;
+    }
+    config_path = config_filename_func(ctx);
+    if (config_path == NULL) {
+        flb_plg_error(ctx->ins, "error getting config path");
+        return FLB_FALSE;
+    }
+    /* No symlink support on Windows; best-effort unlink of the path */
+    flb_plg_info(ctx->ins, "deleting config path: %s", config_path);
+    if (unlink(config_path) != 0) {
+        flb_plg_warn(ctx->ins, "unable to delete config path: %s", config_path);
+    }
+    flb_sds_destroy(config_path);
+    return FLB_TRUE;
+}
+ #endif
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
{
struct cfl_array *confs;
struct cfl_array *tconfs;
flb_sds_t glob_files = NULL;
flb_sds_t config_path;
char realname[CALYPTIA_MAX_DIR_SIZE] = {0};
ssize_t len;
char *ext;
int idx;
struct stat entry_stat;
const char *entry_path;
if (ctx == NULL) {
return -1;
}
if (generate_base_fleet_directory(ctx, &glob_files) == NULL) {
flb_sds_destroy(glob_files);
return -1;
return FLB_FALSE;
}
if (ctx->fleet_config_legacy_format) {
if (flb_sds_cat_safe(&glob_files, PATH_SEPARATOR "*.conf", strlen(PATH_SEPARATOR "*.conf")) != 0) {
flb_sds_destroy(glob_files);
return -1;
}
} else if (flb_sds_cat_safe(&glob_files, PATH_SEPARATOR "*.yaml", strlen(PATH_SEPARATOR "*.yaml")) != 0) {
flb_sds_destroy(glob_files);
return -1;
/* Get the symlink path and extract prefix from its target */
config_path = config_filename_func(ctx);
if (config_path == NULL) {
flb_plg_error(ctx->ins, "error getting config path");
return FLB_FALSE;
}
confs = read_glob(glob_files);
if (confs == NULL) {
flb_sds_destroy(glob_files);
return -1;
/* Follow the symlink to get the target filename */
len = readlink(config_path, realname, sizeof(realname) - 1);
if (len < 0 || len >= (sizeof(realname) - 1)) {
flb_plg_error(ctx->ins, "error resolving symlink: %s", config_path);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
realname[len] = '\0';
tconfs = cfl_array_create(1);
if (tconfs == NULL) {
flb_sds_destroy(glob_files);
cfl_array_destroy(confs);
return -1;
/* Replace the extension with a glob (e.g. "/a/b.yaml" -> "/a/b*") */
ext = strrchr(realname, '.');
if (ext == NULL) {
flb_plg_error(ctx->ins, "symlink target has no extension: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
strcpy(ext, "*");
if (cfl_array_resizable(tconfs, FLB_TRUE) != 0) {
flb_sds_destroy(glob_files);
cfl_array_destroy(confs);
return -1;
/* Delete all files and directories that match the prefix pattern */
confs = read_glob(realname);
if (confs == NULL) {
flb_plg_warn(ctx->ins, "config glob did not return any files: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
for (idx = 0; idx < confs->entry_count; idx++) {
if (fleet_config_path_timestamp(ctx, confs->entries[idx]->data.as_string) > 0) {
cfl_array_append_string(tconfs, confs->entries[idx]->data.as_string);
entry_path = confs->entries[idx]->data.as_string;
if (stat(entry_path, &entry_stat) == 0) {
if (S_ISDIR(entry_stat.st_mode)) {
flb_plg_info(ctx->ins, "deleting config directory: %s", entry_path);
if (delete_dir(entry_path) == FLB_FALSE) {
flb_plg_warn(ctx->ins, "unable to delete config directory: %s", entry_path);
}
} else {
flb_plg_info(ctx->ins, "deleting config file: %s", entry_path);
if (unlink(entry_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config file: %s", entry_path);
}
}
}
}
qsort(tconfs->entries, tconfs->entry_count,
sizeof(struct cfl_variant *),
cfl_array_qsort_conf_files);
for (idx = 0; idx < (((ssize_t)tconfs->entry_count) -3); idx++) {
unlink(tconfs->entries[idx]->data.as_string);
calyptia_config_delete_old_dir(tconfs->entries[idx]->data.as_string);
flb_plg_info(ctx->ins, "deleting config symlink: %s", config_path);
if (unlink(config_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config symlink: %s", config_path);
}
cfl_array_destroy(confs);
cfl_array_destroy(tconfs);
flb_sds_destroy(glob_files);
return 0;
flb_sds_destroy(config_path);
return FLB_TRUE;
}
#ifndef FLB_SYSTEM_WINDOWS
static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
{
struct cfl_array *confs;
flb_sds_t config_path;
char realname[CALYPTIA_MAX_DIR_SIZE] = {0};
ssize_t len;
char *ext;
int idx;
struct stat entry_stat;
const char *entry_path;
if (ctx == NULL) {
return FLB_FALSE;
}
/* Get the symlink path and extract prefix from its target */
config_path = config_filename_func(ctx);
if (config_path == NULL) {
flb_plg_error(ctx->ins, "error getting config path");
return FLB_FALSE;
}
/* Follow the symlink to get the target filename */
len = readlink(config_path, realname, sizeof(realname) - 1);
if (len < 0 || len >= (sizeof(realname) - 1)) {
flb_plg_error(ctx->ins, "error resolving symlink: %s", config_path);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
realname[len] = '\0';
/* Replace the extension with a glob (e.g. "/a/b.yaml" -> "/a/b*") */
ext = strrchr(realname, '.');
if (ext == NULL) {
flb_plg_error(ctx->ins, "symlink target has no extension: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
strcpy(ext, "*");
/* Delete all files and directories that match the prefix pattern */
confs = read_glob(realname);
if (confs == NULL) {
flb_plg_warn(ctx->ins, "config glob did not return any files: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
for (idx = 0; idx < confs->entry_count; idx++) {
entry_path = confs->entries[idx]->data.as_string;
if (stat(entry_path, &entry_stat) == 0) {
if (S_ISDIR(entry_stat.st_mode)) {
flb_plg_info(ctx->ins, "deleting config directory: %s", entry_path);
if (delete_dir(entry_path) == FLB_FALSE) {
flb_plg_warn(ctx->ins, "unable to delete config directory: %s", entry_path);
}
}
else {
flb_plg_info(ctx->ins, "deleting config file: %s", entry_path);
if (unlink(entry_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config file: %s", entry_path);
}
}
}
}
flb_plg_info(ctx->ins, "deleting config symlink: %s", config_path);
if (unlink(config_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config symlink: %s", config_path);
}
cfl_array_destroy(confs);
flb_sds_destroy(config_path);
return FLB_TRUE;
}
#else
static int calyptia_config_delete_by_symlink(struct flb_in_calyptia_fleet_config *ctx,
flb_sds_t (*config_filename_func)(struct flb_in_calyptia_fleet_config *))
{
flb_sds_t config_path;
if (ctx == NULL) {
return FLB_FALSE;
}
config_path = config_filename_func(ctx);
if (config_path == NULL) {
flb_plg_error(ctx->ins, "error getting config path");
return FLB_FALSE;
}
/* No symlink support on Windows; best-effort unlink of the path */
flb_plg_info(ctx->ins, "deleting config path: %s", config_path);
if (unlink(config_path) != 0) {
flb_plg_warn(ctx->ins, "unable to delete config path: %s", config_path);
}
flb_sds_destroy(config_path);
return FLB_TRUE;
}
#endif

Comment on lines 1372 to 1376
if (confs == NULL) {
flb_plg_warn(ctx->ins, "config glob did not return any files: %s", realname);
flb_sds_destroy(config_path);
return FLB_FALSE;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Do not bail out early on glob miss; still unlink the symlink

Per the PR objective, when the glob finds nothing you should still delete the symlink. Currently you return early and skip unlinking.

Apply this diff:

-    confs = read_glob(realname);
-    if (confs == NULL) {
-        flb_plg_warn(ctx->ins, "config glob did not return any files: %s", realname);
-        flb_sds_destroy(config_path);
-        return FLB_FALSE;
-    }
-    for (idx = 0; idx < confs->entry_count; idx++) {
+    confs = read_glob(realname);
+    if (confs == NULL) {
+        flb_plg_warn(ctx->ins, "config glob did not return any files: %s", realname);
+    }
+    else {
+        for (idx = 0; idx < confs->entry_count; idx++) {
         entry_path = confs->entries[idx]->data.as_string;
         if (stat(entry_path, &entry_stat) == 0) {
             if (S_ISDIR(entry_stat.st_mode)) {
                 flb_plg_info(ctx->ins, "deleting config directory: %s", entry_path);
                 if (delete_dir(entry_path) == FLB_FALSE) {
                     flb_plg_warn(ctx->ins, "unable to delete config directory: %s", entry_path);
                 }
             } else {
                 flb_plg_info(ctx->ins, "deleting config file: %s", entry_path);
                 if (unlink(entry_path) != 0) {
                     flb_plg_warn(ctx->ins, "unable to delete config file: %s", entry_path);
                 }
             }
         }
-    }
+        }
+        cfl_array_destroy(confs);
+    }
@@
-    cfl_array_destroy(confs);
     flb_sds_destroy(config_path);
     return FLB_TRUE;

Also applies to: 1394-1397, 1399-1401

🤖 Prompt for AI Agents
In plugins/in_calyptia_fleet/in_calyptia_fleet.c around lines 1372-1376 (and
similarly at 1394-1397 and 1399-1401): the code returns early when flb_glob
returns NULL which skips unlinking the symlink; change the control flow so that
after logging the warning and destroying config_path you still perform the
unlink of realname (and any needed cleanup) instead of returning from the
function, and then continue without dereferencing confs; apply the same fix to
the other two locations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant