Skip to content

feat(gemini): An Ansible playbook to configure and manage log rotation for critical system logs, ensuring disk space is optimized and historical data is safely archived.#4252

Open
polsala wants to merge 1 commit intomainfrom
ai/gemini-20260418-1256
Open

feat(gemini): An Ansible playbook to configure and manage log rotation for critical system logs, ensuring disk space is optimized and historical data is safely archived.#4252
polsala wants to merge 1 commit intomainfrom
ai/gemini-20260418-1256

Conversation

@polsala
Copy link
Copy Markdown
Owner

@polsala polsala commented Apr 18, 2026

Implementation Summary

  • Utility: nightly-ansible-log-guardian
  • Provider: gemini
  • Location: ansible-playbooks/nightly-nightly-ansible-log-guardian
  • Files Created: 6
  • Description: An Ansible playbook to configure and manage log rotation for critical system logs, ensuring disk space is optimized and historical data is safely archived.

Rationale

  • Automated proposal from the Gemini generator delivering a fresh community utility.
  • This utility was generated using the gemini AI provider.

Why safe to merge

  • Utility is isolated to ansible-playbooks/nightly-nightly-ansible-log-guardian.
  • README + tests ship together (see folder contents).
  • No secrets or credentials touched.
  • All changes are additive and self-contained.

Test Plan

  • Follow the instructions in the generated README at ansible-playbooks/nightly-nightly-ansible-log-guardian/README.md
  • Run tests located in ansible-playbooks/nightly-nightly-ansible-log-guardian/tests/

Links

  • Generated docs and examples committed alongside this change.

Mock Justification

  • Not applicable; generator did not introduce new mocks.

…n for critical system logs, ensuring disk space is optimized and historical data is safely archived.
@polsala
Copy link
Copy Markdown
Owner Author

polsala commented Apr 18, 2026

🤖 Review by GROQ Agent

✅ What's solid

  • Clear purpose & isolation – The playbook lives in its own folder (nightly‑nightly‑ansible‑log‑guardian) and does not touch existing code‑bases, making it easy to adopt or remove.
  • Idempotent tasks – Using ansible.builtin.package and ansible.builtin.template ensures the playbook can be re‑run safely without side‑effects.
  • Variable‑driven design – All log‑rotation specifics are driven from vars/main.yml, which makes extending or customizing the utility straightforward.
  • Handler for immediate reload – Providing a Reload logrotate configuration handler gives users an optional way to apply changes instantly, which is handy for testing.
  • Self‑contained README – The documentation explains prerequisites, usage, and a dry‑run command, lowering the barrier for new contributors.

🧪 Tests

  • Good coverage of file creation – The test suite creates a temporary /tmp/logrotate.d_test directory, renders the Jinja2 template, and asserts both existence and key content strings.
  • Use of slurp + b64decode – This pattern reliably checks rendered file content without relying on the target host’s shell utilities.

Opportunities for improvement

  1. Validate Jinja2 rendering directly

    • Add a task that renders the template to a variable (set_fact) and asserts the exact structure with ansible.builtin.assert. This catches syntax errors early, e.g.:
    - name: Render template to variable
      ansible.builtin.template:
        src: ../src/logrotate_config.j2
        dest: /dev/null
        mode: "0644"
        vars:
          item: "{{ log_guardian_configs[0] }}"
      register: rendered
    - name: Assert rendered content contains required directives
      ansible.builtin.assert:
        that:
          - "'rotate 7' in rendered.content"
  2. Leverage ansible-lint in CI

    • Include a lint step (ansible-lint -p src/) to catch style issues (e.g., missing become: true on privileged tasks, deprecated modules).
  3. Test handler execution

    • Currently the handler is defined but never triggered in the test suite. Add a task that forces a change (e.g., touch a dummy file) and then asserts that the handler runs, perhaps by checking a marker file:
    - name: Trigger handler by updating a config
      ansible.builtin.copy:
        dest: "/tmp/logrotate.d_test/{{ item.name }}"
        content: "{{ lookup('template', '../src/logrotate_config.j2') }}"
      loop: "{{ log_guardian_configs }}"
      notify: Reload logrotate configuration
    
    - name: Verify handler ran (creates marker)
      ansible.builtin.stat:
        path: "/tmp/logrotate.handler_ran"
      register: handler_check
  4. Add a syntax‑check test

    • Run ansible-playbook --syntax-check src/log_guardian.yml as part of the test suite to guarantee the playbook parses correctly on every commit.

🔒 Security

  • Privilege escalation – The playbook correctly uses become: yes for tasks that modify system files. Ensure the inventory (or playbook) does not unintentionally grant become to untrusted hosts. Consider adding become_method: sudo explicitly to avoid defaults that might differ across environments.

  • File permissions – The generated logrotate files are owned by root:root with mode 0644. This is appropriate for most distributions, but double‑check that the create directive inside the logrotate config (e.g., "0640 root adm") matches the target system’s group policies.

  • No secret handling – The playbook does not reference any credentials, which is good. Ensure future extensions keep this discipline (e.g., avoid embedding API keys in vars).

  • Handler command safetylogrotate -f /etc/logrotate.conf forces an immediate rotation. In production this could cause a brief spike in I/O. Document the impact and consider making the handler optional via a variable, e.g.:

    - name: Reload logrotate configuration
      ansible.builtin.command: logrotate -f /etc/logrotate.conf
      when: log_guardian_force_reload | default(false)

🧩 Docs/DX

  • README completeness – The README covers installation, configuration, and execution. A few tweaks could make onboarding smoother:

    1. Add a quick‑start example – Show a minimal vars/main.yml with a single log entry, then the exact command to run.
    2. Explain the postrotate field – Mention that the command runs as root and that failures are ignored (|| true).
    3. Document the test workflow – Include a “Running the test suite locally” section that points to the required Ansible version and any environment variables.
    4. Link to upstream logrotate docs – Providing a reference helps users understand the directives they can use.
  • Variable documentation – Consider adding a README.vars.md or a comment block at the top of vars/main.yml that enumerates each supported key, its type, and default values. This reduces guesswork for contributors.

  • Consistent naming – The folder name repeats “nightly” (nightly-nightly-ansible-log-guardian). If this is intentional for your naming convention, keep it; otherwise, a single “nightly‑ansible‑log‑guardian” would be cleaner.

🧱 Mocks/Fakes

  • Mocking package installation – The test uses a debug task to “mock” the logrotate package. While acceptable for a quick sanity check, a more realistic approach is to use the ansible.builtin.package module with state: present and set check_mode: true to verify idempotence without actually installing anything:

    - name: Verify package would be installed (check mode)
      ansible.builtin.package:
        name: logrotate
        state: present
      check_mode: true
      register: pkg_check
    - name: Assert package check succeeded
      ansible.builtin.assert:
        that: pkg_check.changed == false
  • Isolation of /etc/logrotate.d – Redirecting output to /tmp/logrotate.d_test is a solid strategy. To make the playbook itself more test‑friendly, consider parameterizing the destination directory via a variable (e.g., logrotate_dest_dir) with a default of /etc/logrotate.d. The test can then override it without needing to patch the playbook.

  • Handler mock – As noted above, the handler is not exercised in the current test suite. Introducing a mock marker file (created by the handler) would give confidence that notifications are wired correctly.

  • Avoid hard‑coded inventory – The test inventory only contains localhost. If future contributors add hosts, the test could inadvertently affect real machines. Guard the test run with an environment variable or a --extra-vars "test_mode=true" flag that forces the playbook to use the temporary directory and skips the real handler.


Overall impression: The addition brings valuable automation for log management and follows good Ansible practices. By tightening the test coverage (handler verification, linting, syntax checks) and polishing the documentation, the utility will be robust, secure, and easy for the team to adopt.

@polsala
Copy link
Copy Markdown
Owner Author

polsala commented Apr 18, 2026

🤖 Review by GROQ Agent

✅ What's solid

  • Clear purpose & scope – the playbook is nicely isolated under ansible‑playbooks/nightly‑nightly‑ansible‑log‑guardian and does one thing (logrotate configuration).
  • Self‑contained documentation – the README explains the problem, the features, prerequisites, usage, and how to run the test suite.
  • Variable‑driven designvars/main.yml lets users declaratively describe each log rotation policy, making the playbook reusable across environments.
  • Idempotent tasks – using the template module with a loop guarantees that the configuration files are only updated when the rendered content changes.
  • Handler for immediate reload – the Reload logrotate configuration handler gives a quick way to verify the new config during testing.
  • Test suite – the tests/test_log_guardian.yml playbook exercises the core logic without touching the real /etc/logrotate.d directory, which is great for CI safety.

🧪 Tests

Observation Recommendation
Tests only exercise the template step and a mocked package install. Add a test that runs the full log_guardian.yml playbook (perhaps with --check) against the mock /tmp/logrotate.d_test directory to verify the handler is triggered and that the playbook reports “changed” only when appropriate.
The test suite uses ansible.builtin.debug to “mock” the package installation. Replace the debug task with a real package task wrapped in check_mode: true or use ansible.builtin.pip/ansible.builtin.yum with state=present and update_cache: no. This gives a more realistic outcome while still being safe in CI.
Assertions on file content rely on find() string checks. Consider using ansible.builtin.assert with a regular‑expression match (match) for more robust validation, e.g.:
```yaml
- name: Assert daily rotation
ansible.builtin.assert:
that:
- "'daily' in (shelter_sentry_content.content
No test for handler execution (logrotate reload). Add a task that checks the handler was notified, e.g.:
yaml<br>- name: Verify handler was triggered<br> ansible.builtin.meta: flush_handlers<br>- name: Assert logrotate was run<br> ansible.builtin.command: cat /tmp/logrotate.d_test/{{ item.name }}<br> register: dummy<br> (or use ansible.builtin.assert on ansible_facts['ansible_run_handlers']).
Test environment cleanup is good, but the file task that removes /tmp/logrotate.d_test runs after the assertions. Move the cleanup to a post_tasks block or use always: to guarantee removal even if a test fails.

🔒 Security

  • Least‑privilege escalationbecome: yes is set at the play level, which is fine for a system‑wide configuration, but you could scope it to the tasks that truly need root (package install, template to /etc/logrotate.d). Example:
    yaml<br>- name: Ensure logrotate package is installed<br> ansible.builtin.package:<br> name: logrotate<br> state: present<br> become: true<br> This reduces the attack surface if the playbook is run against a host where the user has limited sudo rights.
  • Variable sanitisationitem.path is interpolated directly into the Jinja template. If a user supplies a malicious path (e.g., containing backticks or $(...)), it could be written into the config and later executed by logrotate. Consider adding a simple validation step:
    yaml<br>- name: Validate log path<br> ansible.builtin.assert:<br> that:<br> - item.path is match('^/[^\\s]*$')<br> fail_msg: "Invalid log path {{ item.path }}"<br> loop: "{{ log_guardian_configs }}"<br> |
  • Handler commandlogrotate -f /etc/logrotate.conf forces an immediate rotation, which could be disruptive on production systems. For a safer default, change the handler to a no‑op in production and only enable it in the test environment:
    yaml<br>- name: Reload logrotate configuration (test only)<br> ansible.builtin.command: logrotate -f /etc/logrotate.conf<br> when: ansible_env['ANSIBLE_LOG_GUARDIAN_TEST'] | default(false) | bool<br> |
  • File permissions – the generated config files are owned by root:root with mode 0644. That is appropriate, but ensure the playbook does not expose the vars/main.yml file (which may contain sensitive paths) to non‑privileged users. Consider adding no_log: true on any task that might echo variable values in debug output.

🧩 Docs / Developer Experience

  • README enhancements

    • Add a quick‑start section that shows a minimal vars/main.yml example (maybe just one log) so newcomers can copy‑paste.
    • Document the supported OS families (Debian/Ubuntu vs RHEL/CentOS) and any differences in the default logrotate package name.
    • Explain the handler behavior and how to disable it in production (as suggested above).
    • Provide a link to the upstream logrotate man page for reference.
  • Variable defaults – ship a vars/main.yml.example with sensible defaults and a comment block explaining each field. This helps users avoid committing their own copy of the file with secrets.

  • Ansible linting – run ansible-lint as part of CI and add a comment in the README about the linting command, e.g.:
    bash<br>ansible-lint ansible-playbooks/nightly-nightly-ansible-log-guardian/src/log_guardian.yml<br>

  • Version pinning – specify the minimum Ansible version required (e.g., >=2.12) in the README and optionally in a requirements.yml file.

  • Directory layout – the double “nightly‑nightly” in the path looks like a typo. Consider renaming the folder to nightly-ansible-log-guardian for consistency and to avoid confusion in CI scripts.

🧱 Mocks / Fakes

  • Current approach – the test suite creates a temporary /tmp/logrotate.d_test directory and redirects the template destination there. This is a solid way to avoid privileged writes.

  • Improvement suggestions

    • Use ansible.builtin.copy with content: to generate a minimal mock logrotate.conf in the temp directory, then run the handler against that mock config. This gives a more realistic end‑to‑end test.
    • Replace the debug “Mock logrotate package installation” task with a meta: noop or a package task that runs in check_mode. This keeps the test deterministic while still exercising the module path.
    • Consider leveraging ansible-test’s mock plugin to stub out the package module, which would make the test suite faster and more isolated.
  • Future extensibility – if additional providers (e.g., aws, gcp) are added later, factor the mock directory path into a variable (logrotate_test_dir) so the same test file can be reused with different back‑ends.


Overall, the contribution delivers a useful, well‑documented Ansible utility. The suggestions above focus on tightening security, expanding test coverage, polishing the documentation, and making the mock strategy a bit more robust. Implementing these tweaks will improve maintainability and confidence when the playbook is run in production environments.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant