Skip to content

Commit 4a2e05e

Browse files
authored
DPE-5355 Ensure logs flushes (#543)
* ensure flush runs and some refactor * var names * text fix * add parameter to setup call * version bump * install file with correct permission * format refactor
1 parent c9aae8b commit 4a2e05e

File tree

11 files changed

+68
-52
lines changed

11 files changed

+68
-52
lines changed

config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ options:
1313
profile:
1414
description: |
1515
profile representing the scope of deployment, and used to be able to enable high-level
16-
high-level customisation of sysconfigs, resource checks/allocation, warning levels, etc.
16+
customisation of sysconfigs, resource checks/allocation, warning levels, etc.
1717
Allowed values are: “production” and “testing”.
1818
type: string
1919
default: production

lib/charms/mysql/v0/mysql.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def wait_until_mysql_connection(self) -> None:
133133
# Increment this major API version when introducing breaking changes
134134
LIBAPI = 0
135135

136-
LIBPATCH = 77
136+
LIBPATCH = 78
137137

138138
UNIT_TEARDOWN_LOCKNAME = "unit-teardown"
139139
UNIT_ADD_LOCKNAME = "unit-add"
@@ -1004,7 +1004,7 @@ def render_mysqld_configuration( # noqa: C901
10041004
"log_error": f"{snap_common}/var/log/mysql/error.log",
10051005
"general_log": "ON",
10061006
"general_log_file": f"{snap_common}/var/log/mysql/general.log",
1007-
"slow_query_log_file": f"{snap_common}/var/log/mysql/slowquery.log",
1007+
"slow_query_log_file": f"{snap_common}/var/log/mysql/slow.log",
10081008
"binlog_expire_logs_seconds": f"{binlog_retention_seconds}",
10091009
"loose-audit_log_policy": "LOGINS",
10101010
"loose-audit_log_file": f"{snap_common}/var/log/mysql/audit.log",

src/charm.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ def _on_config_changed(self, _) -> None:
297297
self._mysql.write_content_to_file(
298298
path=MYSQLD_CUSTOM_CONFIG_FILE, content=new_config_content
299299
)
300+
self._mysql.setup_logrotate_and_cron(self.text_logs)
300301

301302
if (
302303
self.mysql_config.keys_requires_restart(changed_config)
@@ -620,6 +621,17 @@ def unit_address(self) -> str:
620621
"""Returns the unit's address."""
621622
return self.get_unit_address(self.unit)
622623

624+
@property
625+
def text_logs(self) -> list:
626+
"""Enabled text logs."""
627+
# slow logs isn't enabled by default
628+
text_logs = ["error", "general"]
629+
630+
if self.config.plugin_audit_enabled:
631+
text_logs.append("audit")
632+
633+
return text_logs
634+
623635
def install_workload(self) -> bool:
624636
"""Exponential backoff retry to install and configure MySQL.
625637
@@ -654,7 +666,7 @@ def workload_initialise(self) -> None:
654666
self.hostname_resolution.update_etc_hosts(None)
655667

656668
self._mysql.write_mysqld_config()
657-
self._mysql.setup_logrotate_and_cron()
669+
self._mysql.setup_logrotate_and_cron(self.text_logs)
658670
self._mysql.reset_root_password_and_start_mysqld()
659671
self._mysql.configure_mysql_users()
660672

src/flush_mysql_logs.py

+1
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ def _flush_mysql_logs(self, _) -> None:
6060
return
6161

6262
self.charm._mysql.flush_mysql_logs(text_logs)
63+
logger.debug(f"Flushed {text_logs.lower()}")

src/mysql_vm_helpers.py

+31-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import subprocess
1313
import tempfile
1414
import typing
15-
from typing import Dict, List, Optional, Tuple
15+
from typing import Dict, Iterable, List, Optional, Tuple
1616

1717
import jinja2
1818
from charms.mysql.v0.mysql import (
@@ -280,29 +280,48 @@ def write_mysqld_config(self) -> None:
280280
content=content_str,
281281
)
282282

283-
def setup_logrotate_and_cron(self) -> None:
284-
"""Create and write the logrotate config file."""
283+
def setup_logrotate_and_cron(self, enabled_log_files: Iterable) -> None:
284+
"""Setup log rotation configuration for text files.
285+
286+
Args:
287+
enabled_log_files: a iterable of enabled text logs
288+
"""
285289
logger.debug("Creating logrotate config file")
290+
config_path = "/etc/logrotate.d/flush_mysql_logs"
291+
script_path = f"{self.charm.charm_dir}/logrotation.sh"
292+
cron_path = "/etc/cron.d/flush_mysql_logs"
293+
logs_dir = f"{CHARMED_MYSQL_COMMON_DIRECTORY}/var/log/mysql"
286294

287295
with open("templates/logrotate.j2", "r") as file:
288296
template = jinja2.Template(file.read())
289297

290-
rendered = template.render(
298+
logrotate_conf_content = template.render(
291299
system_user=MYSQL_SYSTEM_USER,
292-
snap_common_directory=CHARMED_MYSQL_COMMON_DIRECTORY,
300+
log_dir=logs_dir,
293301
charm_directory=self.charm.charm_dir,
294302
unit_name=self.charm.unit.name,
303+
enabled_log_files=enabled_log_files,
295304
)
296305

297-
with open("/etc/logrotate.d/flush_mysql_logs", "w") as file:
298-
file.write(rendered)
306+
self.write_content_to_file(
307+
config_path, logrotate_conf_content, owner="root", permission=0o644
308+
)
299309

300-
cron = (
301-
"* 1-23 * * * root logrotate -f /etc/logrotate.d/flush_mysql_logs\n"
302-
"1-59 0 * * * root logrotate -f /etc/logrotate.d/flush_mysql_logs\n"
310+
with open("templates/run_log_rotation.sh.j2", "r") as file:
311+
template = jinja2.Template(file.read())
312+
313+
logrotation_script_content = template.render(
314+
log_path=f"{CHARMED_MYSQL_COMMON_DIRECTORY}/var/log/mysql",
315+
enabled_log_files=enabled_log_files,
316+
logrotate_conf=config_path,
317+
owner=MYSQL_SYSTEM_USER,
318+
group=MYSQL_SYSTEM_USER,
303319
)
304-
with open("/etc/cron.d/flush_mysql_logs", "w") as file:
305-
file.write(cron)
320+
321+
self.write_content_to_file(script_path, logrotation_script_content, permission=0o550)
322+
323+
cron_content = f"* 1-23 * * * root {script_path}\n1-59 0 * * * root {script_path}\n"
324+
self.write_content_to_file(cron_path, cron_content, owner="root")
306325

307326
def reset_root_password_and_start_mysqld(self) -> None:
308327
"""Reset the root user password and start mysqld."""

src/upgrade.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def _on_upgrade_granted(self, event: UpgradeGrantedEvent) -> None: # noqa: C901
199199
self.charm._mysql.start_mysqld()
200200
if self.charm.config.plugin_audit_enabled:
201201
self.charm._mysql.install_plugins(["audit_log", "audit_log_filter"])
202-
self.charm._mysql.setup_logrotate_and_cron()
202+
self.charm._mysql.setup_logrotate_and_cron(self.charm.text_logs)
203203
except VersionError:
204204
logger.exception("Failed to upgrade MySQL dependencies")
205205
self.set_unit_failed()

templates/logrotate.j2

+5-29
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,14 @@ nomail
2121
nosharedscripts
2222
nocopytruncate
2323

24-
{{ snap_common_directory }}/var/log/mysql/error.log {
25-
olddir archive_error
24+
{% for log in enabled_log_files %}
25+
{{ log_dir }}/{{ log }}.log {
26+
olddir archive_{{ log }}
2627
postrotate
2728
juju_command=/usr/bin/juju-run
2829
if command -v /usr/bin/juju-exec; then juju_command=/usr/bin/juju-exec; fi
29-
"$juju_command" -u {{ unit_name }} LOGS_TYPE=ERROR JUJU_DISPATCH_PATH=hooks/flush_mysql_logs {{ charm_directory }}/dispatch
30+
"$juju_command" -u {{ unit_name }} LOGS_TYPE={{ log|upper }} JUJU_DISPATCH_PATH=hooks/flush_mysql_logs {{ charm_directory }}/dispatch
3031
endscript
3132
}
33+
{% endfor %}
3234

33-
{{ snap_common_directory }}/var/log/mysql/general.log {
34-
olddir archive_general
35-
postrotate
36-
juju_command=/usr/bin/juju-run
37-
if command -v /usr/bin/juju-exec; then juju_command=/usr/bin/juju-exec; fi
38-
"$juju_command" -u {{ unit_name }} LOGS_TYPE=GENERAL JUJU_DISPATCH_PATH=hooks/flush_mysql_logs {{ charm_directory }}/dispatch
39-
endscript
40-
}
41-
42-
{{ snap_common_directory }}/var/log/mysql/slowquery.log {
43-
olddir archive_slowquery
44-
postrotate
45-
juju_command=/usr/bin/juju-run
46-
if command -v /usr/bin/juju-exec; then juju_command=/usr/bin/juju-exec; fi
47-
"$juju_command" -u {{ unit_name }} LOGS_TYPE=SLOW JUJU_DISPATCH_PATH=hooks/flush_mysql_logs {{ charm_directory }}/dispatch
48-
endscript
49-
}
50-
51-
{{ snap_common_directory }}/var/log/mysql/audit.log {
52-
olddir archive_audit
53-
postrotate
54-
juju_command=/usr/bin/juju-run
55-
if command -v /usr/bin/juju-exec; then juju_command=/usr/bin/juju-exec; fi
56-
"$juju_command" -u {{ unit_name }} LOGS_TYPE=AUDIT JUJU_DISPATCH_PATH=hooks/flush_mysql_logs {{ charm_directory }}/dispatch
57-
endscript
58-
}

templates/run_log_rotation.sh.j2

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
3+
# install files to ensure flush runs
4+
{% for log in enabled_log_files %}
5+
[[ -f "{{ log_path }}/{{ log }}.log" ]] || install -o "{{ owner }}" -g "{{ group }}" -m 640 /dev/null "{{ log_path }}/{{ log }}.log"
6+
{% endfor %}
7+
8+
logrotate -f {{ logrotate_conf }}
9+
10+
# vim: set filetype=sh
11+

tests/integration/high_availability/test_replication.py

-3
Original file line numberDiff line numberDiff line change
@@ -356,13 +356,11 @@ async def test_log_rotation(ops_test: OpsTest, highly_available_cluster) -> None
356356
app = get_application_name(ops_test, "mysql")
357357
unit = ops_test.model.applications[app].units[0]
358358

359-
# Exclude slowquery log files as slowquery logs are not enabled by default
360359
log_types = ["error", "general", "audit"]
361360
log_files = ["error.log", "general.log", "audit.log"]
362361
archive_directories = [
363362
"archive_error",
364363
"archive_general",
365-
"archive_slowquery",
366364
"archive_audit",
367365
]
368366

@@ -418,7 +416,6 @@ async def test_log_rotation(ops_test: OpsTest, highly_available_cluster) -> None
418416
), f"❌ unexpected files/directories in log directory: {ls_la_output}"
419417

420418
logger.info("Ensuring log files were rotated")
421-
# Exclude checking slowquery log rotation as slowquery logs are disabled by default
422419
for log in set(log_types):
423420
file_contents = await read_contents_from_file_in_unit(
424421
ops_test, unit, f"{CHARMED_MYSQL_COMMON_DIRECTORY}/var/log/mysql/{log}.log"

tests/unit/test_mysql.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1882,7 +1882,7 @@ def test_render_mysqld_configuration(self, _get_available_memory):
18821882
"log_error": "/var/log/mysql/error.log",
18831883
"general_log": "ON",
18841884
"general_log_file": "/var/log/mysql/general.log",
1885-
"slow_query_log_file": "/var/log/mysql/slowquery.log",
1885+
"slow_query_log_file": "/var/log/mysql/slow.log",
18861886
"binlog_expire_logs_seconds": "604800",
18871887
"loose-audit_log_format": "JSON",
18881888
"loose-audit_log_policy": "LOGINS",

tests/unit/test_mysqlsh_helpers.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ def test_write_mysqld_config(
291291
"log_error = /var/snap/charmed-mysql/common/var/log/mysql/error.log",
292292
"general_log = ON",
293293
"general_log_file = /var/snap/charmed-mysql/common/var/log/mysql/general.log",
294-
"slow_query_log_file = /var/snap/charmed-mysql/common/var/log/mysql/slowquery.log",
294+
"slow_query_log_file = /var/snap/charmed-mysql/common/var/log/mysql/slow.log",
295295
"binlog_expire_logs_seconds = 604800",
296296
"loose-audit_log_policy = LOGINS",
297297
"loose-audit_log_file = /var/snap/charmed-mysql/common/var/log/mysql/audit.log",
@@ -334,7 +334,7 @@ def test_write_mysqld_config(
334334
"log_error = /var/snap/charmed-mysql/common/var/log/mysql/error.log",
335335
"general_log = ON",
336336
"general_log_file = /var/snap/charmed-mysql/common/var/log/mysql/general.log",
337-
"slow_query_log_file = /var/snap/charmed-mysql/common/var/log/mysql/slowquery.log",
337+
"slow_query_log_file = /var/snap/charmed-mysql/common/var/log/mysql/slow.log",
338338
"binlog_expire_logs_seconds = 604800",
339339
"loose-audit_log_policy = LOGINS",
340340
"loose-audit_log_file = /var/snap/charmed-mysql/common/var/log/mysql/audit.log",

0 commit comments

Comments
 (0)