Add logrotate resource

This commit is contained in:
Salamandar 2023-06-12 15:12:28 +02:00
parent e1569f962b
commit d3fb796edf

View file

@ -22,7 +22,7 @@ import shutil
import random import random
import tempfile import tempfile
import subprocess import subprocess
from typing import Dict, Any, List from typing import Tuple, Dict, Any, List
from moulinette import m18n from moulinette import m18n
from moulinette.utils.process import check_output from moulinette.utils.process import check_output
@ -147,15 +147,23 @@ class AppResource:
self.manager = manager self.manager = manager
for key, value in self.default_properties.items(): for key, value in self.default_properties.items():
if isinstance(value, str): value = self.fill_args_placeholders(value)
value = value.replace("__APP__", self.app)
setattr(self, key, value) setattr(self, key, value)
for key, value in properties.items(): for key, value in properties.items():
if isinstance(value, str): value = self.fill_args_placeholders(value)
value = value.replace("__APP__", self.app)
setattr(self, key, value) setattr(self, key, value)
def fill_args_placeholders(value: Any) -> str:
if isinstance(value, str):
return string.replace("__APP__", self.app)
if isinstance(value, list):
return [self.fill_args_placeholders(subval) for subval in value]
if isinstance(value, dict):
return {key: self.fill_args_placeholders(subval) for key, subval in value.items()}
def get_setting(self, key): def get_setting(self, key):
from yunohost.app import app_setting from yunohost.app import app_setting
@ -1337,4 +1345,86 @@ class DatabaseAppResource(AppResource):
self.delete_setting("db_pwd") self.delete_setting("db_pwd")
class LogrotateAppResource(AppResource):
"""
Use Logrotate to manage the app's log file. It
##### Example
```toml
[resources.logrotate]
logfile = "/var/log/myapp"
user = "app_user"
```
Or an array of logrotates:
```toml
[[resources.logrotate]]
logfile = "/var/log/myapp/log1.log"
[[resources.logrotate]]
logfile = "/var/log/myapp/log2.log"
user = "app_user"
```
##### Properties
- `logfile`: The log file or directory
- `user`: The database type, either `mysql` or `postgresql`
nonappend is not exposed because you can define a list of logrotates.
##### Provision/Update
- Creates /etc/logrotate.d/$app
##### Deprovision
- Deletes /etc/logrotate.d/$app
"""
# Notes for future?
# Remove support for the non-list syntax ?
# deep_clean -> ..
# backup -> backup /etc/logrotate.d/$app
# restore -> restore /etc/logrotate.d/$app
type = "logrotate"
priority = 80
default_properties: Dict[str, Any] = {
"logfile": "/var/log/__APP__",
"user": None,
}
logrotates: List[Dict[str, Any]] = []
def __init__(self, properties: Tuple[Dict[str, Any], List[Dict[str, Any]]], *args, **kwargs):
# Do not provide properties, we will set them afterwards
super().__init__({}, *args, **kwargs)
# A dict is just a one-element list
if isinstance(properties, dict):
properties = [properties]
if len(self.logrotates) < 1:
raise YunohostError("resources.logrotate is an empty array, need at least one element!")
for logrotate in properties:
self.logrotate += self.default_properties | self.fill_args_placeholders(logrotate)
@staticmethod()
def use_logrotate_for(data: Dict[str, Any], append: bool) -> str:
command = f"ynh_use_logrotate --logfile={data['logfile']}"
if data["user"]:
command += f"--specific_user={data['user']}"
if not append:
command += "--nonappend"
def provision_or_update(self, context: Dict = {}):
script = [self.use_logrotate_for(self.logrotates[0], False)]
script += [self.use_logrotate_for(logrotate, True) for logrotate in self.logrotates[1:]]
self._run_script("provision_or_update", "\n".join(script))
def deprovision(self, context: Dict = {}):
script = "ynh_remove_logrotate"
self._run_script("deprovision", script)
AppResourceClassesByType = {c.type: c for c in AppResource.__subclasses__()} AppResourceClassesByType = {c.type: c for c in AppResource.__subclasses__()}