Merge ~hloeung/content-cache-charm:master into content-cache-charm:master

Proposed by Haw Loeung
Status: Merged
Approved by: Haw Loeung
Approved revision: d41c9dc3479613feea34852eef119db866846054
Merged at revision: 340cde9bd9636762cdae12b6770b874c8231641c
Proposed branch: ~hloeung/content-cache-charm:master
Merge into: content-cache-charm:master
Diff against target: 254 lines (+144/-4)
9 files modified
config.yaml (+5/-0)
lib/utils.py (+24/-0)
reactive/content_cache.py (+22/-4)
tests/unit/files/haproxy-dateext-logrotate.conf (+12/-0)
tests/unit/files/haproxy-logrotate.conf (+11/-0)
tests/unit/files/nginx-dateext-logrotate.conf (+19/-0)
tests/unit/files/nginx-logrotate.conf (+18/-0)
tests/unit/test_content_cache.py (+17/-0)
tests/unit/test_utils.py (+16/-0)
Reviewer Review Type Date Requested Status
Joel Sing (community) +1 Approve
Haw Loeung ptal Needs Resubmitting
Canonical IS Reviewers Pending
Review via email: mp+374496@code.launchpad.net

Commit message

Enable dateext and allow overriding log retention - LP: #1848407

Description of the change

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
Joel Sing (jsing) :
review: Needs Fixing
Revision history for this message
Haw Loeung (hloeung) :
review: Needs Resubmitting (ptal)
Revision history for this message
Joel Sing (jsing) wrote :

LGTM

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

Change successfully merged at revision 340cde9bd9636762cdae12b6770b874c8231641c

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/config.yaml b/config.yaml
2index 4166111..fddb691 100644
3--- a/config.yaml
4+++ b/config.yaml
5@@ -19,6 +19,11 @@ options:
6 default: "/var/lib/nginx/proxy"
7 description: >
8 Path or directory to store cached objects.
9+ log_retention:
10+ type: int
11+ default: 30
12+ description: >
13+ Number of log files to retain during rotation.
14 nagios_context:
15 type: string
16 default: "juju"
17diff --git a/lib/utils.py b/lib/utils.py
18index 66e94da..b3f0dfb 100644
19--- a/lib/utils.py
20+++ b/lib/utils.py
21@@ -1,5 +1,6 @@
22 import hashlib
23 import hmac
24+import os
25 import re
26 import shutil
27 import subprocess
28@@ -136,3 +137,26 @@ def tls_cipher_suites(tls_cipher_suites):
29 except Exception:
30 raise InvalidTLSCiphersError('Unable to parse provided OpenSSL cipher string "{}"'.format(tls_cipher_suites))
31 return tls_cipher_suites
32+
33+
34+def logrotate(path, retention=30, dateext=True):
35+ if not os.path.exists(path):
36+ return None
37+
38+ with open(path, 'r', encoding='utf-8') as f:
39+ config = f.read().split('\n')
40+
41+ new = []
42+ regex = re.compile('^(\\s+)(rotate|dateext)')
43+ for line in config:
44+ m = regex.match(line)
45+ if m:
46+ if m.group(2) == 'dateext':
47+ continue
48+ if dateext:
49+ new.append('{}dateext'.format(m.group(1)))
50+ new.append('{}rotate {}'.format(m.group(1), retention))
51+ else:
52+ new.append(line)
53+
54+ return '\n'.join(new)
55diff --git a/reactive/content_cache.py b/reactive/content_cache.py
56index d001775..592588e 100644
57--- a/reactive/content_cache.py
58+++ b/reactive/content_cache.py
59@@ -149,6 +149,7 @@ def configure_nginx(conf_path=None):
60 if changed:
61 service_start_or_restart('nginx')
62
63+ update_logrotate('nginx', retention=config.get('log_retention'))
64 reactive.set_flag('content_cache.nginx.configured')
65
66
67@@ -273,6 +274,7 @@ def configure_haproxy():
68 if haproxy.write(rendered_config):
69 service_start_or_restart('haproxy')
70
71+ update_logrotate('haproxy', retention=config.get('log_retention'))
72 reactive.set_flag('content_cache.haproxy.configured')
73
74
75@@ -471,16 +473,32 @@ def _interpolate_secrets_origin_headers(headers, secrets):
76 return headers
77
78
79-def copy_file(source_path, dest_path, perms=0o644, owner=None, group=None):
80+def update_logrotate(service, retention, dateext=True):
81+ conf_path = os.path.join('/etc/logrotate.d', service)
82+ write_file(utils.logrotate(conf_path, retention=retention, dateext=dateext), conf_path)
83+
84+
85+def copy_file(source_path, dest_path, **kwargs):
86 """Copy a file from the charm directory onto the local filesystem.
87
88- Returns True if the file was copied, False if the file already exists and
89- is identical.
90+ Reads the contents of source_path and passes through to write_file().
91+ Please see the help for write_file() for argument usage.
92 """
93
94- # Compare and only write out file on change.
95 with open(source_path, 'r') as f:
96 source = f.read()
97+ return write_file(source, dest_path, **kwargs)
98+
99+
100+def write_file(source, dest_path, perms=0o644, owner=None, group=None):
101+ """Write a source string to a file.
102+
103+ Returns True if the file was modified (new file, file changed, file
104+ deleted), False if the file is not modified or is intentionally not
105+ created.
106+ """
107+
108+ # Compare and only write out file on change.
109 dest = ''
110 if os.path.exists(dest_path):
111 with open(dest_path, 'r') as f:
112diff --git a/tests/unit/files/haproxy-dateext-logrotate.conf b/tests/unit/files/haproxy-dateext-logrotate.conf
113new file mode 100644
114index 0000000..9f4a9e3
115--- /dev/null
116+++ b/tests/unit/files/haproxy-dateext-logrotate.conf
117@@ -0,0 +1,12 @@
118+/var/log/haproxy.log {
119+ daily
120+ dateext
121+ rotate 52
122+ missingok
123+ notifempty
124+ compress
125+ delaycompress
126+ postrotate
127+ invoke-rc.d rsyslog rotate >/dev/null 2>&1 || true
128+ endscript
129+}
130diff --git a/tests/unit/files/haproxy-logrotate.conf b/tests/unit/files/haproxy-logrotate.conf
131new file mode 100644
132index 0000000..442dc4e
133--- /dev/null
134+++ b/tests/unit/files/haproxy-logrotate.conf
135@@ -0,0 +1,11 @@
136+/var/log/haproxy.log {
137+ daily
138+ rotate 52
139+ missingok
140+ notifempty
141+ compress
142+ delaycompress
143+ postrotate
144+ invoke-rc.d rsyslog rotate >/dev/null 2>&1 || true
145+ endscript
146+}
147diff --git a/tests/unit/files/nginx-dateext-logrotate.conf b/tests/unit/files/nginx-dateext-logrotate.conf
148new file mode 100644
149index 0000000..a098eb2
150--- /dev/null
151+++ b/tests/unit/files/nginx-dateext-logrotate.conf
152@@ -0,0 +1,19 @@
153+/var/log/nginx/*.log {
154+ daily
155+ missingok
156+ dateext
157+ rotate 14
158+ compress
159+ delaycompress
160+ notifempty
161+ create 0640 www-data adm
162+ sharedscripts
163+ prerotate
164+ if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
165+ run-parts /etc/logrotate.d/httpd-prerotate; \
166+ fi \
167+ endscript
168+ postrotate
169+ invoke-rc.d nginx rotate >/dev/null 2>&1
170+ endscript
171+}
172diff --git a/tests/unit/files/nginx-logrotate.conf b/tests/unit/files/nginx-logrotate.conf
173new file mode 100644
174index 0000000..423c6ad
175--- /dev/null
176+++ b/tests/unit/files/nginx-logrotate.conf
177@@ -0,0 +1,18 @@
178+/var/log/nginx/*.log {
179+ daily
180+ missingok
181+ rotate 14
182+ compress
183+ delaycompress
184+ notifempty
185+ create 0640 www-data adm
186+ sharedscripts
187+ prerotate
188+ if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
189+ run-parts /etc/logrotate.d/httpd-prerotate; \
190+ fi \
191+ endscript
192+ postrotate
193+ invoke-rc.d nginx rotate >/dev/null 2>&1
194+ endscript
195+}
196diff --git a/tests/unit/test_content_cache.py b/tests/unit/test_content_cache.py
197index 537a081..0107b6a 100644
198--- a/tests/unit/test_content_cache.py
199+++ b/tests/unit/test_content_cache.py
200@@ -58,6 +58,10 @@ class TestCharm(unittest.TestCase):
201 self.addCleanup(patcher.stop)
202 self.mock_cpu_count.return_value = 4
203
204+ patcher = mock.patch('reactive.content_cache.update_logrotate')
205+ self.mock_update_logrotate = patcher.start()
206+ self.addCleanup(patcher.stop)
207+
208 status.active.reset_mock()
209 status.blocked.reset_mock()
210 status.maintenance.reset_mock()
211@@ -664,6 +668,19 @@ site1.local:
212 want = {'site1.local': {'locations': {'/': {'signed-url-hmac-key': 'Maiqu7ohmeiSh6ooroa0'}}}}
213 self.assertEqual(content_cache.interpolate_secrets(config, secrets), want)
214
215+ def test_write_file(self):
216+ source = '# User-provided config added here'
217+ dest = os.path.join(self.tmpdir, '90-content-cache.conf')
218+
219+ self.assertTrue(content_cache.write_file(source, dest))
220+ # Write again, should return False and not True per above.
221+ self.assertFalse(content_cache.write_file(source, dest))
222+
223+ # Check contents
224+ with open(dest, 'r') as f:
225+ got = f.read()
226+ self.assertEqual(got, source)
227+
228 def test_copy_file(self):
229 source = os.path.join(self.charm_dir, 'files/nginx-logging-format.conf')
230 dest = os.path.join(self.tmpdir, os.path.basename(source))
231diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py
232index ac7c417..0bb3d5a 100644
233--- a/tests/unit/test_utils.py
234+++ b/tests/unit/test_utils.py
235@@ -133,3 +133,19 @@ class TestLibUtils(unittest.TestCase):
236 tls_cipher_suites = '--help'
237 with self.assertRaises(utils.InvalidTLSCiphersError):
238 utils.tls_cipher_suites(tls_cipher_suites)
239+
240+ def test_logrotate(self):
241+ with open('tests/unit/files/haproxy-dateext-logrotate.conf') as f:
242+ self.assertEqual(utils.logrotate(retention=52, path='tests/unit/files/haproxy-logrotate.conf'), f.read())
243+ with open('tests/unit/files/nginx-dateext-logrotate.conf') as f:
244+ self.assertEqual(utils.logrotate(retention=14, path='tests/unit/files/nginx-logrotate.conf'), f.read())
245+
246+ # Test dateext removal.
247+ with open('tests/unit/files/nginx-logrotate.conf') as f:
248+ self.assertEqual(
249+ utils.logrotate(retention=14, dateext=False, path='tests/unit/files/nginx-dateext-logrotate.conf'),
250+ f.read(),
251+ )
252+
253+ # Test when config file doesn't exist.
254+ self.assertEqual(utils.logrotate(retention=14, path='tests/unit/files/some-file-that-doesnt-exist'), None)

Subscribers

People subscribed via source and target branches