Merge ~mertkirpici/charm-logrotated:lp/2017795 into charm-logrotated:master

Proposed by Mert Kirpici
Status: Merged
Approved by: Mert Kirpici
Approved revision: 7316795355629d4ebcfe8a2b76f5faf0f5b07d23
Merged at revision: 55f7ed6f91b9a56f0241e68a4ef5c6cd75fd5492
Proposed branch: ~mertkirpici/charm-logrotated:lp/2017795
Merge into: charm-logrotated:master
Diff against target: 218 lines (+118/-22)
5 files modified
src/lib/lib_cron.py (+18/-19)
src/tests/functional/test_logrotate.py (+21/-0)
src/tests/unit/conftest.py (+7/-1)
src/tests/unit/requirements.txt (+1/-1)
src/tests/unit/test_logrotate.py (+71/-1)
Reviewer Review Type Date Requested Status
🤖 prod-jenkaas-bootstack (community) continuous-integration Approve
Chi Wai CHAN Approve
Erhan Sunar (community) Approve
BootStack Reviewers Pending
Review via email: mp+442359@code.launchpad.net

Commit message

LP #2017795

Description of the change

fix: cleanup old cronjobs upon config change

    A change in cronjob frequency used to leave the old cronjobs behind,
    causing unnecessary execution. This patch is mitigating that behavior
    and also adds some tests.

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
Erhan Sunar (esunar) wrote :

LGTM

review: Approve
Revision history for this message
Chi Wai CHAN (raychan96) wrote :

LGTM

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Failed to merge change (unable to merge source repository due to conflicts), setting status to needs review.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Approve (continuous-integration)
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 55f7ed6f91b9a56f0241e68a4ef5c6cd75fd5492

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/lib/lib_cron.py b/src/lib/lib_cron.py
2index be3dff9..1f30ddc 100644
3--- a/src/lib/lib_cron.py
4+++ b/src/lib/lib_cron.py
5@@ -48,13 +48,13 @@ class CronHelper:
6 If logrotate-cronjob config option is set to True install cronjob,
7 otherwise cleanup.
8 """
9- clean_up_file = self.cronjob_frequency if self.cronjob_enabled else -1
10+ self.cleanup_cronjob_files()
11
12 if self.cronjob_enabled is True:
13 cronjob_path = os.path.realpath(__file__)
14 cron_file_path = (
15 self.cronjob_base_path
16- + self.cronjob_check_paths[clean_up_file]
17+ + self.cronjob_check_paths[self.cronjob_frequency]
18 + "/"
19 + self.cronjob_logrotate_cron_file
20 )
21@@ -73,25 +73,24 @@ class CronHelper:
22 os.chmod(cron_file_path, 700)
23
24 # update cron.daily schedule if logrotate-cronjob-frequency set to "daily"
25- if self.validate_cron_conf() and self.cronjob_frequency == 1:
26+ if self.cronjob_frequency == 1 and self.validate_cron_conf():
27 self.update_cron_daily_schedule()
28+ else:
29+ self.cleanup_etc_config()
30
31- self.cleanup_cronjob(clean_up_file)
32-
33- def cleanup_cronjob(self, frequency=-1):
34- """Cleanup previous config."""
35- if frequency == -1:
36- for check_path in self.cronjob_check_paths:
37- path = (
38- self.cronjob_base_path
39- + check_path
40- + "/"
41- + self.cronjob_logrotate_cron_file
42- )
43- if os.path.exists(path):
44- os.remove(path)
45- if os.path.exists(self.cronjob_etc_config):
46- os.remove(self.cronjob_etc_config)
47+ def cleanup_cronjob_files(self):
48+ """Cleanup previous cronjob files."""
49+ for check_path in self.cronjob_check_paths:
50+ path = os.path.join(
51+ self.cronjob_base_path + check_path, self.cronjob_logrotate_cron_file
52+ )
53+ if os.path.exists(path):
54+ os.remove(path)
55+
56+ def cleanup_etc_config(self):
57+ """Cleanup the saved config in /etc directory."""
58+ if os.path.exists(self.cronjob_etc_config):
59+ os.remove(self.cronjob_etc_config)
60
61 def update_logrotate_etc(self):
62 """Run logrotate update config."""
63diff --git a/src/tests/functional/test_logrotate.py b/src/tests/functional/test_logrotate.py
64index 4aa0aa6..0afbb82 100644
65--- a/src/tests/functional/test_logrotate.py
66+++ b/src/tests/functional/test_logrotate.py
67@@ -112,6 +112,27 @@ async def test_configure_cron_daily(deploy_app):
68 assert deploy_app.status == "active"
69
70
71+async def test_reconfigure_cronjob_frequency(model, deploy_app, unit, jujutools):
72+ """Test reconfiguration of cronjob frequency."""
73+ await deploy_app.set_config({"logrotate-cronjob-frequency": "weekly"})
74+ await model.block_until(lambda: deploy_app.status == "active")
75+ config = await deploy_app.get_config()
76+
77+ result = await jujutools.run_command(
78+ "test -f /etc/cron.weekly/charm-logrotate", unit
79+ )
80+ weekly_cronjob_exists = result["return-code"] == 0
81+
82+ result = await jujutools.run_command(
83+ "test -f /etc/cron.daily/charm-logrotate", unit
84+ )
85+ daily_cronjob_exists = result["return-code"] == 0
86+
87+ assert config["logrotate-cronjob-frequency"]["value"] == "weekly"
88+ assert not daily_cronjob_exists
89+ assert weekly_cronjob_exists
90+
91+
92 async def test_configure_override_01(model, deploy_app, jujutools, unit):
93 """Test configuring override for the deployment (interval)."""
94 test_path = "/etc/logrotate.d/apt"
95diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py
96index 1f15b42..9eff063 100644
97--- a/src/tests/unit/conftest.py
98+++ b/src/tests/unit/conftest.py
99@@ -1,7 +1,7 @@
100 #!/usr/bin/python3
101 """Configurations for tests."""
102
103-import mock
104+from unittest import mock
105
106 import pytest
107
108@@ -54,6 +54,12 @@ def mock_remote_unit(monkeypatch):
109 monkeypatch.setattr("lib_logrotate.hookenv.remote_unit", lambda: "unit-mock/0")
110
111
112+@pytest.fixture()
113+def mock_local_unit(monkeypatch):
114+ """Local unit mock."""
115+ monkeypatch.setattr("lib_logrotate.hookenv.local_unit", lambda: "unit-logrotated/0")
116+
117+
118 @pytest.fixture
119 def mock_charm_dir(monkeypatch):
120 """Charm dir mock."""
121diff --git a/src/tests/unit/requirements.txt b/src/tests/unit/requirements.txt
122index 9c685e5..3d4047b 100644
123--- a/src/tests/unit/requirements.txt
124+++ b/src/tests/unit/requirements.txt
125@@ -1,5 +1,5 @@
126 charmhelpers
127 charms.reactive
128-mock
129 pytest
130 pytest-cov
131+pytest-mock
132\ No newline at end of file
133diff --git a/src/tests/unit/test_logrotate.py b/src/tests/unit/test_logrotate.py
134index 0c89bbc..8d329e5 100644
135--- a/src/tests/unit/test_logrotate.py
136+++ b/src/tests/unit/test_logrotate.py
137@@ -1,6 +1,7 @@
138 """Main unit test module."""
139-
140 import json
141+import os
142+from textwrap import dedent
143 from unittest import mock
144
145 from lib_logrotate import LogrotateHelper
146@@ -279,3 +280,72 @@ class TestCronHelper:
147 cron_config.validate_cron_conf()
148
149 assert err.type == cron_config.InvalidCronConfig
150+
151+ def test_install_cronjob(self, cron, mock_local_unit, mocker):
152+ """Test install cronjob method."""
153+ mock_charm_dir = "/mock/unit-logrotated-0/charm"
154+ mock_exists = mocker.patch("lib_cron.os.path.exists", return_value=True)
155+ mock_remove = mocker.patch("lib_cron.os.remove")
156+ mock_chmod = mocker.patch("lib_cron.os.chmod")
157+ mocker.patch(
158+ "lib_cron.os.path.realpath",
159+ return_value=os.path.join(mock_charm_dir, "lib/lib_cron.py"),
160+ )
161+ mocker.patch("lib_cron.os.getcwd", return_value=mock_charm_dir)
162+ mock_open = mocker.patch("lib_cron.open")
163+ mock_handle = mock_open.return_value
164+
165+ expected_files_to_be_removed = [
166+ "/etc/cron.hourly/charm-logrotate",
167+ "/etc/cron.daily/charm-logrotate",
168+ "/etc/cron.weekly/charm-logrotate",
169+ "/etc/cron.monthly/charm-logrotate",
170+ ]
171+
172+ cron_config = cron()
173+ cron_config.cronjob_enabled = True
174+ cron_config.cronjob_frequency = 2
175+ cron_config.install_cronjob()
176+
177+ mock_exists.assert_has_calls(
178+ [mock.call(file) for file in expected_files_to_be_removed], any_order=True
179+ )
180+ mock_remove.assert_has_calls(
181+ [mock.call(file) for file in expected_files_to_be_removed], any_order=True
182+ )
183+ mock_open.assert_called_once_with("/etc/cron.weekly/charm-logrotate", "w")
184+ mock_handle.write.assert_called_once_with(
185+ dedent(
186+ """\
187+ #!/bin/bash
188+ /usr/bin/sudo /usr/bin/juju-run unit-logrotated/0 "/mock/unit-logrotated-0/.venv/bin/python3 /mock/unit-logrotated-0/charm/lib/lib_cron.py"
189+ """ # noqa
190+ )
191+ )
192+ mock_handle.close.assert_called_once()
193+ mock_chmod.assert_called_once_with("/etc/cron.weekly/charm-logrotate", 700)
194+
195+ def test_install_cronjob_removes_etc_config_when_cronjob_disabled(
196+ self, cron, mocker
197+ ):
198+ """Test that all cronjob related files created upon cronjobs being disabled."""
199+ mock_exists = mocker.patch("lib_cron.os.path.exists", return_value=True)
200+ mock_remove = mocker.patch("lib_cron.os.remove")
201+
202+ expected_files_to_be_removed = [
203+ "/etc/cron.hourly/charm-logrotate",
204+ "/etc/cron.daily/charm-logrotate",
205+ "/etc/cron.weekly/charm-logrotate",
206+ "/etc/cron.monthly/charm-logrotate",
207+ "/etc/logrotate_cronjob_config",
208+ ]
209+ cron_config = cron()
210+ cron_config.cronjob_enabled = False
211+ cron_config.install_cronjob()
212+
213+ mock_exists.assert_has_calls(
214+ [mock.call(file) for file in expected_files_to_be_removed], any_order=True
215+ )
216+ mock_remove.assert_has_calls(
217+ [mock.call(file) for file in expected_files_to_be_removed], any_order=True
218+ )

Subscribers

People subscribed via source and target branches

to all changes: