Add fucntion to import a config file

This commit is contained in:
JonnyWong16 2020-07-15 23:26:22 -07:00
parent beff5caaac
commit 06665fdd06
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
2 changed files with 115 additions and 3 deletions

View file

@ -190,6 +190,56 @@ _CONFIG_DEFINITIONS = {
_BLACKLIST_KEYS = ['_APITOKEN', '_TOKEN', '_KEY', '_SECRET', '_PASSWORD', '_APIKEY', '_ID', '_HOOK'] _BLACKLIST_KEYS = ['_APITOKEN', '_TOKEN', '_KEY', '_SECRET', '_PASSWORD', '_APIKEY', '_ID', '_HOOK']
_WHITELIST_KEYS = ['HTTPS_KEY'] _WHITELIST_KEYS = ['HTTPS_KEY']
_DO_NOT_IMPORT_KEYS = [
'FIRST_RUN_COMPLETE', 'GET_FILE_SIZES_HOLD', 'GIT_PATH',
'BACKUP_DIR', 'CACHE_DIR', 'LOG_DIR', 'NEWSLETTER_DIR', 'NEWSLETTER_CUSTOM_DIR',
'HTTP_HOST', 'HTTP_PORT', 'HTTP_ROOT',
'HTTP_USERNAME', 'HTTP_PASSWORD', 'HTTP_HASH_PASSWORD', 'HTTP_HASHED_PASSWORD',
'ENABLE_HTTPS', 'HTTPS_CREATE_CERT', 'HTTPS_CERT', 'HTTPS_CERT_CHAIN', 'HTTPS_KEY'
]
_DO_NOT_IMPORT_KEYS_DOCKER = [
'PLEXPY_AUTO_UPDATE', 'GIT_REMOTE', 'GIT_BRANCH'
]
IS_IMPORTING = False
def set_is_importing(value):
global IS_IMPORTING
IS_IMPORTING = value
def import_tautulli_config(config=None, backup=False):
if backup:
# Make a backup of the current config first
logger.info("Tautulli Config :: Creating a config backup before importing.")
if not make_backup():
logger.error("Tautulli Config :: Failed to import Tautulli config: failed to create config backup")
return False
logger.info("Tautulli Config :: Importing Tautulli config '%s'...", config)
set_is_importing(True)
# Create a new Config object with the imported config file
imported_config = Config(config, is_import=True)
# Remove keys that should not be imported
for key in _DO_NOT_IMPORT_KEYS:
delattr(imported_config, key)
if plexpy.DOCKER:
for key in _DO_NOT_IMPORT_KEYS_DOCKER:
delattr(imported_config, key)
# Merge the imported config file into the current config file
plexpy.CONFIG._config.merge(imported_config._config)
plexpy.CONFIG.write()
logger.info("Tautulli Config :: Tautulli config import complete.")
set_is_importing(False)
# Restart to apply changes
plexpy.SIGNAL = 'restart'
def make_backup(cleanup=False, scheduler=False): def make_backup(cleanup=False, scheduler=False):
""" Makes a backup of config file, removes all but the last 5 backups """ """ Makes a backup of config file, removes all but the last 5 backups """
@ -233,14 +283,15 @@ def make_backup(cleanup=False, scheduler=False):
class Config(object): class Config(object):
""" Wraps access to particular values in a config file """ """ Wraps access to particular values in a config file """
def __init__(self, config_file): def __init__(self, config_file, is_import=False):
""" Initialize the config with values from a file """ """ Initialize the config with values from a file """
self._config_file = config_file self._config_file = config_file
self._config = ConfigObj(self._config_file, encoding='utf-8') self._config = ConfigObj(self._config_file, encoding='utf-8')
for key in _CONFIG_DEFINITIONS: for key in _CONFIG_DEFINITIONS:
self.check_setting(key) self.check_setting(key)
self._upgrade() if not is_import:
self._blacklist() self._upgrade()
self._blacklist()
def _blacklist(self): def _blacklist(self):
""" Add tokens and passwords to blacklisted words in logger """ """ Add tokens and passwords to blacklisted words in logger """
@ -337,6 +388,16 @@ class Config(object):
self._config[section][ini_key] = definition_type(value) self._config[section][ini_key] = definition_type(value)
return self._config[section][ini_key] return self._config[section][ini_key]
def __delattr__(self, name):
"""
Deletes a key from the configuration object.
"""
if not re.match(r'[A-Z_]+$', name):
return super(Config, self).__delattr__(name)
else:
key, definition_type, section, ini_key, default = self._define(name)
del self._config[section][ini_key]
def process_kwargs(self, kwargs): def process_kwargs(self, kwargs):
""" """
Given a big bunch of key value pairs, apply them to the ini. Given a big bunch of key value pairs, apply them to the ini.

View file

@ -3832,6 +3832,57 @@ class WebInterface(object):
else: else:
return {'result': 'error', 'message': 'App not recognized for import'} return {'result': 'error', 'message': 'App not recognized for import'}
@cherrypy.expose
@cherrypy.tools.json_out()
@requireAuth(member_of("admin"))
@addtoapi()
def import_config(self, config_file=None, config_path=None, backup=False, **kwargs):
""" Import a Tautulli config file.
```
Required parameters:
config_file (file): The config file to import (multipart/form-data)
or
config_path (str): The full path to the config file to import
Optional parameters:
backup (bool): true or false whether to backup
the current config before importing
Returns:
json:
{"result": "success",
"message": "Config import has started. Check the logs to monitor any problems. "
"Tautulli will restart automatically."
}
```
"""
if database.IS_IMPORTING:
return {'result': 'error',
'message': 'Database import is in progress. Please wait until it is finished to import a config.'}
if config_file:
config_path = os.path.join(plexpy.CONFIG.CACHE_DIR, config_file.filename + '.import.ini')
logger.info("Received config file '%s' for import. Saving to cache '%s'.",
config_file.filename, config_path)
with open(config_path, 'wb') as f:
while True:
data = config_file.file.read(8192)
if not data:
break
f.write(data)
if not config_path:
return {'result': 'error', 'message': 'No config specified for import'}
threading.Thread(target=config.import_tautulli_config,
kwargs={'config': config_path,
'backup': helpers.bool_true(backup)}).start()
return {'result': 'success',
'message': 'Config import has started. Check the logs to monitor any problems. '
'Tautulli will restart automatically.'}
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def import_database_tool(self, app=None, **kwargs): def import_database_tool(self, app=None, **kwargs):