pyinfra icon indicating copy to clipboard operation
pyinfra copied to clipboard

server.crontab() not identifying cronjobs

Open kwilt opened this issue 5 months ago • 6 comments

Describe the bug

If this is not a bug I am horribly confused on how this is actually supposed to work. 🙃

If an unidentified cronjob exists in your crontab and you attempt to identify this cronjob with the cron_name argument, this does not add an identifier to the cronjob. You must then make another call to server.crontab() with the same cron_name if you want to make changes to the cronjob. This time however, instead of overwriting the existing cronjob that you just tried to identify, server.crontab() will create a new entry in your crontab - appending it to the end of the file - leaving you with the cronjob you initially tried to identify as well as the new cronjob with the identifier you tried to apply to the initial cronjob.

To Reproduce

Have a crontab with some cronjobs in it that aren't identified by PyInfra, then run server.crontab() against your crontab in an attempt to identify the cronjobs, and then modify them afterwards.

  • Operation code & usage
server.crontab(
    name="Identify Cron",
    command=f"/usr/bin/php{php_version} {old_estore_dir}/bin/magento cron:run 2>&1 \
| grep -v \"Ran jobs by schedule\" >> {old_estore_dir}/var/log/magento.cron.log",
    minute="*",
    hour="*",
    month="*",
    day_of_week="*",
    day_of_month="*",
    present=True,
    user=f"{username}",
    cron_name=f"{site}_cron",
    _sudo=True,
)

server.crontab(
    name="Modify Cron",
    command=f"/usr/bin/php{php_version} {estore_dir}/bin/magento cron:run 2>&1 \
| grep -v \"Ran jobs by schedule\" >> {estore_dir}/var/log/magento.cron.log",
    minute="*",
    hour="*",
    month="*",
    day_of_week="*",
    day_of_month="*",
    present=True,
    user=f"{username}",
    cron_name=f"{site}_cron",
    _sudo=True,
)

If I attempt to identify and modify either of the cronjobs, I get a brand new cronjob appended to the end of the file as shown, with the cron identifier. In this example I tried to edit the staging_cron

Before

* * * * * /usr/bin/php8.2 /opt/<name>/apps/prod/estore.e483eac1/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/prod/estore.e483eac1/var/log/magento.cron.log

* * * * * /usr/bin/php8.2 /opt/<name>/apps/staging/estore.1312e8dd/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/staging/estore.1312e8dd/var/log/magento.cron.log

After

* * * * * /usr/bin/php8.2 /opt/<name>/apps/prod/estore.e483eac1/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/prod/estore.e483eac1/var/log/magento.cron.log

* * * * * /usr/bin/php8.2 /opt/<name>/apps/staging/estore.1312e8dd/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/staging/estore.1312e8dd/var/log/magento.cron.log

# pyinfra-name=staging_cron
* * * * * /usr/bin/php8.2 /opt/<name>/apps/staging/estore.656bc6af/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/staging/estore.656bc6af/var/log/magento.cron.log

Expected behavior

The cronjob should be identified with the first call to server.crontab(), prepending the cron_name identifier/comment on the line above the cronjob. Then, the second call to server.crontab() should overwrite this cronjob with the new contents if the same cron_name is used, not appending a new cronjob to the end of the file, and not leaving the initial cronjob behind.

Meta

System: Linux
      Platform: Linux-5.15.153.1-microsoft-standard-WSL2-x86_64-with-glibc2.35
      Release: 5.15.153.1-microsoft-standard-WSL2
      Machine: x86_64
    pyinfra: v3.1
      click: v8.1.7
      configparser: v7.1.0
      distro: v1.9.0
      gevent: v24.2.1
      jinja2: v3.1.4
      packaging: v24.1
      paramiko: v3.4.1
      python-dateutil: v2.9.0.post0
      pywinrm: v0.5.0
      setuptools: v73.0.1
      typeguard: v4.3.0
      typing-extensions: v4.12.2
      wheel: v0.44.0
    Executable: /home/<name>/<project>/env/bin/pyinfra
    Python: 3.10.12 (CPython, GCC 11.4.0)
  • How was pyinfra installed? Pip

  • Debug info:

--> Starting operation: Identify Cron
    [pyinfra.api.operations] Starting operation {'Identify Cron'} on @local
    [pyinfra.api.facts] Getting fact: server.Crontab (user=<name>) (ensure_hosts: None)

[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c '! command -v crontab >/dev/null || crontab -l -u <name> || true'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
    [pyinfra.api.facts] [@local] Loaded fact server.Crontab (user=<name>)
    [pyinfra.api.host] [@local] noop: crontab /usr/bin/php8.2 /opt/<name>/apps/staging/estore.1312e8dd/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/staging/estore.1312e8dd/var/log/magento.cron.log exists
    [@local] No changes

--> Starting operation: Modify Cron
    [pyinfra.api.operations] Starting operation {'Modify Cron'} on @local
    [pyinfra.api.facts] Getting fact: server.Crontab (user=<name>) (ensure_hosts: None)

[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c '! command -v crontab >/dev/null || crontab -l -u <name> || true'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
    [pyinfra.api.facts] [@local] Loaded fact server.Crontab (user=<name>)

[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c 'crontab -l -u <name>> /tmp/pyinfra-99800753387583ff6590a828b5571df23d46c9b6'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c 'echo '"'"''"'"' >> /tmp/pyinfra-99800753387583ff6590a828b5571df23d46c9b6'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c 'echo '"'"'# pyinfra-name=staging_cron'"'"' >> /tmp/pyinfra-99800753387583ff6590a828b5571df23d46c9b6'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c 'echo '"'"'* * * * * /usr/bin/php8.2 /opt/<name>/apps/staging/estore.656bc6af/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /opt/<name>/apps/staging/estore.656bc6af/var/log/magento.cron.log'"'"' >> /tmp/pyinfra-99800753387583ff6590a828b5571df23d46c9b6'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
[pyinfra.connectors.local] --> Running command on localhost: sudo -H -n sh -c 'crontab -u <name> /tmp/pyinfra-99800753387583ff6590a828b5571df23d46c9b6'
[pyinfra.connectors.util] --> Waiting for exit status...
[pyinfra.connectors.util] --> Command exit status: 0
    [@local] Success

kwilt avatar Aug 28 '24 22:08 kwilt