Add ${RANDOM} variable to config file

This commit is contained in:
Orsiris de Jong 2023-02-02 20:14:19 +01:00
parent 4551cbe485
commit 74259dc7b7
3 changed files with 71 additions and 28 deletions

View file

@ -37,7 +37,10 @@ repo:
prometheus:
## Supervision
metrics: true
backup_job: ${HOSTNAME} # ${HOSTNAME} is a variable which can be replaced with a constant string
# ${HOSTNAME} is a variable
# ${RANDOM}[n] is a variable containing 'n' random alphanumeric char
# The following example allows to have multiple hosts with the same hostname
backup_job: ${HOSTNAME}-${RANDOM}
# Prometheus metrics destination can be a http / https server with optional basic authentication (pushgateway), or a file path for node textfile collector to pickup
destination: # https://push.monitoring.example.tld/metrics/job/${BACKUP_JOB} where ${BACKUP_JOB} is defined in prometheus_backup_job
# prometheus instance, becomes exported_instance when using a push gateway
@ -64,4 +67,6 @@ options:
server_password:
# every 10 NPBackup runs, we'll try an autoupgrade. Never set this lower than 2 since failed upgrades will prevent backups from succeeding
interval: 10
backup_admin_password: NPBackup_00
backup_admin_password: NPBackup_00
# Available variables: ${HOSTNAME}, ${RANDOM}[n]
host_identity: ${HOSTNAME}-${RANDOM}[3]

View file

@ -7,15 +7,19 @@ __intname__ = "npbackup.configuration"
__author__ = "Orsiris de Jong"
__copyright__ = "Copyright (C) 2022-2023 NetInvent"
__license__ = "GPL-3.0-only"
__build__ = "2023020101"
__version__ = "1.5.0 for npbackup 2.2.0+"
__build__ = "2023020102"
__version__ = "1.6.0 for npbackup 2.2.0+"
from typing import Tuple, Optional
import sys
from ruamel.yaml import YAML
from logging import getLogger
import re
from cryptidy import symmetric_encryption as enc
from ofunctions.random import random_string
from npbackup.customization import ID_STRING
# Try to import a private key, if not available, fallback to the default key
try:
from npbackup._private_secret_keys import AES_KEY, DEFAULT_BACKUP_ADMIN_PASSWORD
@ -57,7 +61,7 @@ empty_config_dict = {
}
def decrypt_data(config_dict):
def decrypt_data(config_dict: dict) -> dict:
try:
for option in ENCRYPTED_OPTIONS:
try:
@ -95,7 +99,7 @@ def decrypt_data(config_dict):
return config_dict
def encrypt_data(config_dict):
def encrypt_data(config_dict: dict) -> dict:
for option in ENCRYPTED_OPTIONS:
try:
if config_dict[option["section"]][option["name"]]:
@ -121,7 +125,7 @@ def encrypt_data(config_dict):
return config_dict
def is_encrypted(config_dict):
def is_encrypted(config_dict: dict) -> bool:
try:
is_enc = True
for option in ENCRYPTED_OPTIONS:
@ -142,29 +146,62 @@ def is_encrypted(config_dict):
# NoneType
return False
def has_random_variables(config_dict: dict) -> Tuple[bool, dict]:
"""
Replaces ${RANDOM}[n] with n random alphanumeric chars
"""
is_modified = False
for section in config_dict.keys():
for entry in config_dict[section].keys():
if isinstance(config_dict[section][entry], str):
matches = re.search(r"\${RANDOM}\[(.*)\]", config_dict[section][entry])
print(matches)
if matches:
try:
char_quantity = int(matches.group(1))
except (ValueError, TypeError):
char_quantity = 1
print(random_string(char_quantity))
config_dict[section][entry] = re.sub(r"\${RANDOM}\[.*\]", random_string(char_quantity), config_dict[section][entry])
is_modified = True
return is_modified, config_dict
def load_config(config_file):
def load_config(config_file: str) -> Optional[dict]:
"""
Using ruamel.yaml preserves comments and order of yaml files
"""
logger.debug("Using configuration file {}".format(config_file))
with open(config_file, "r", encoding="utf-8") as file_handle:
# RoundTrip loader is default and preserves comments and ordering
yaml = YAML(typ="rt")
config_dict = yaml.load(file_handle)
if not is_encrypted(config_dict):
logger.info("Encrypting non encrypted data in configuration file")
config_dict = encrypt_data(config_dict)
save_config(config_file, config_dict)
try:
logger.debug("Using configuration file {}".format(config_file))
with open(config_file, "r", encoding="utf-8") as file_handle:
# RoundTrip loader is default and preserves comments and ordering
yaml = YAML(typ="rt")
config_dict = yaml.load(file_handle)
is_modified, config_dict = has_random_variables(config_dict)
if is_modified:
logger.info("Handling random variables in configuration files")
save_config(config_file, config_dict)
if not is_encrypted(config_dict):
logger.info("Encrypting non encrypted data in configuration file")
config_dict = encrypt_data(config_dict)
save_config(config_file, config_dict)
config_dict = decrypt_data(config_dict)
return config_dict
except OSError:
logger.critical("Cannot load configuration file from %s", config_file)
return None
def save_config(config_file: str, config_dict: dict) -> bool:
try:
with open(config_file, "w", encoding="utf-8") as file_handle:
if not is_encrypted(config_dict):
config_dict = encrypt_data(config_dict)
yaml = YAML(typ="rt")
yaml.dump(config_dict, file_handle)
# Since we deal with global objects in ruamel.yaml, we need to decrypt after saving
config_dict = decrypt_data(config_dict)
return config_dict
def save_config(config_file, config_dict):
with open(config_file, "w", encoding="utf-8") as file_handle:
if not is_encrypted(config_dict):
config_dict = encrypt_data(config_dict)
yaml = YAML(typ="rt")
yaml.dump(config_dict, file_handle)
# Since we deal with global objects in ruamel.yaml, we need to decrypt after saving
config_dict = decrypt_data(config_dict)
return True
except OSError:
logger.critical("Cannot save configuartion file to %s", config_file)
return False

View file

@ -6,6 +6,7 @@ ofunctions.misc>=1.5.2
ofunctions.process>=1.4.0
ofunctions.threading>=2.0.0
ofunctions.platform>=1.3.0
ofunctions.random
python-pidfile>=3.0.0
pysimplegui>=4.6.0
requests