mirror of
https://github.com/netinvent/npbackup.git
synced 2025-11-10 14:11:23 +08:00
Add ${RANDOM} variable to config file
This commit is contained in:
parent
4551cbe485
commit
74259dc7b7
3 changed files with 71 additions and 28 deletions
|
|
@ -37,7 +37,10 @@ repo:
|
||||||
prometheus:
|
prometheus:
|
||||||
## Supervision
|
## Supervision
|
||||||
metrics: true
|
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
|
# 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
|
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
|
# prometheus instance, becomes exported_instance when using a push gateway
|
||||||
|
|
@ -65,3 +68,5 @@ options:
|
||||||
# every 10 NPBackup runs, we'll try an autoupgrade. Never set this lower than 2 since failed upgrades will prevent backups from succeeding
|
# 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
|
interval: 10
|
||||||
backup_admin_password: NPBackup_00
|
backup_admin_password: NPBackup_00
|
||||||
|
# Available variables: ${HOSTNAME}, ${RANDOM}[n]
|
||||||
|
host_identity: ${HOSTNAME}-${RANDOM}[3]
|
||||||
|
|
@ -7,15 +7,19 @@ __intname__ = "npbackup.configuration"
|
||||||
__author__ = "Orsiris de Jong"
|
__author__ = "Orsiris de Jong"
|
||||||
__copyright__ = "Copyright (C) 2022-2023 NetInvent"
|
__copyright__ = "Copyright (C) 2022-2023 NetInvent"
|
||||||
__license__ = "GPL-3.0-only"
|
__license__ = "GPL-3.0-only"
|
||||||
__build__ = "2023020101"
|
__build__ = "2023020102"
|
||||||
__version__ = "1.5.0 for npbackup 2.2.0+"
|
__version__ = "1.6.0 for npbackup 2.2.0+"
|
||||||
|
|
||||||
|
from typing import Tuple, Optional
|
||||||
import sys
|
import sys
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
import re
|
||||||
from cryptidy import symmetric_encryption as enc
|
from cryptidy import symmetric_encryption as enc
|
||||||
|
from ofunctions.random import random_string
|
||||||
from npbackup.customization import ID_STRING
|
from npbackup.customization import ID_STRING
|
||||||
|
|
||||||
|
|
||||||
# Try to import a private key, if not available, fallback to the default key
|
# Try to import a private key, if not available, fallback to the default key
|
||||||
try:
|
try:
|
||||||
from npbackup._private_secret_keys import AES_KEY, DEFAULT_BACKUP_ADMIN_PASSWORD
|
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:
|
try:
|
||||||
for option in ENCRYPTED_OPTIONS:
|
for option in ENCRYPTED_OPTIONS:
|
||||||
try:
|
try:
|
||||||
|
|
@ -95,7 +99,7 @@ def decrypt_data(config_dict):
|
||||||
return config_dict
|
return config_dict
|
||||||
|
|
||||||
|
|
||||||
def encrypt_data(config_dict):
|
def encrypt_data(config_dict: dict) -> dict:
|
||||||
for option in ENCRYPTED_OPTIONS:
|
for option in ENCRYPTED_OPTIONS:
|
||||||
try:
|
try:
|
||||||
if config_dict[option["section"]][option["name"]]:
|
if config_dict[option["section"]][option["name"]]:
|
||||||
|
|
@ -121,7 +125,7 @@ def encrypt_data(config_dict):
|
||||||
return config_dict
|
return config_dict
|
||||||
|
|
||||||
|
|
||||||
def is_encrypted(config_dict):
|
def is_encrypted(config_dict: dict) -> bool:
|
||||||
try:
|
try:
|
||||||
is_enc = True
|
is_enc = True
|
||||||
for option in ENCRYPTED_OPTIONS:
|
for option in ENCRYPTED_OPTIONS:
|
||||||
|
|
@ -142,25 +146,54 @@ def is_encrypted(config_dict):
|
||||||
# NoneType
|
# NoneType
|
||||||
return False
|
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
|
Using ruamel.yaml preserves comments and order of yaml files
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
logger.debug("Using configuration file {}".format(config_file))
|
logger.debug("Using configuration file {}".format(config_file))
|
||||||
with open(config_file, "r", encoding="utf-8") as file_handle:
|
with open(config_file, "r", encoding="utf-8") as file_handle:
|
||||||
# RoundTrip loader is default and preserves comments and ordering
|
# RoundTrip loader is default and preserves comments and ordering
|
||||||
yaml = YAML(typ="rt")
|
yaml = YAML(typ="rt")
|
||||||
config_dict = yaml.load(file_handle)
|
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):
|
if not is_encrypted(config_dict):
|
||||||
logger.info("Encrypting non encrypted data in configuration file")
|
logger.info("Encrypting non encrypted data in configuration file")
|
||||||
config_dict = encrypt_data(config_dict)
|
config_dict = encrypt_data(config_dict)
|
||||||
save_config(config_file, config_dict)
|
save_config(config_file, config_dict)
|
||||||
config_dict = decrypt_data(config_dict)
|
config_dict = decrypt_data(config_dict)
|
||||||
return config_dict
|
return config_dict
|
||||||
|
except OSError:
|
||||||
|
logger.critical("Cannot load configuration file from %s", config_file)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def save_config(config_file, config_dict):
|
def save_config(config_file: str, config_dict: dict) -> bool:
|
||||||
|
try:
|
||||||
with open(config_file, "w", encoding="utf-8") as file_handle:
|
with open(config_file, "w", encoding="utf-8") as file_handle:
|
||||||
if not is_encrypted(config_dict):
|
if not is_encrypted(config_dict):
|
||||||
config_dict = encrypt_data(config_dict)
|
config_dict = encrypt_data(config_dict)
|
||||||
|
|
@ -168,3 +201,7 @@ def save_config(config_file, config_dict):
|
||||||
yaml.dump(config_dict, file_handle)
|
yaml.dump(config_dict, file_handle)
|
||||||
# Since we deal with global objects in ruamel.yaml, we need to decrypt after saving
|
# Since we deal with global objects in ruamel.yaml, we need to decrypt after saving
|
||||||
config_dict = decrypt_data(config_dict)
|
config_dict = decrypt_data(config_dict)
|
||||||
|
return True
|
||||||
|
except OSError:
|
||||||
|
logger.critical("Cannot save configuartion file to %s", config_file)
|
||||||
|
return False
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ ofunctions.misc>=1.5.2
|
||||||
ofunctions.process>=1.4.0
|
ofunctions.process>=1.4.0
|
||||||
ofunctions.threading>=2.0.0
|
ofunctions.threading>=2.0.0
|
||||||
ofunctions.platform>=1.3.0
|
ofunctions.platform>=1.3.0
|
||||||
|
ofunctions.random
|
||||||
python-pidfile>=3.0.0
|
python-pidfile>=3.0.0
|
||||||
pysimplegui>=4.6.0
|
pysimplegui>=4.6.0
|
||||||
requests
|
requests
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue