uncloud-mravi/uncloud/common/settings.py

133 lines
4.6 KiB
Python
Raw Normal View History

2019-12-21 09:36:55 +00:00
import configparser
import logging
import sys
import os
2020-01-03 13:38:59 +00:00
from datetime import datetime
from uncloud.common.etcd_wrapper import Etcd3Wrapper
from os.path import join as join_path
2019-12-21 09:36:55 +00:00
logger = logging.getLogger(__name__)
class CustomConfigParser(configparser.RawConfigParser):
def __getitem__(self, key):
try:
result = super().__getitem__(key)
except KeyError as err:
raise KeyError(
'Key \'{}\' not found in configuration. Make sure you configure uncloud.'.format(
key
)
) from err
2019-12-21 09:36:55 +00:00
else:
return result
class Settings(object):
def __init__(self):
conf_name = 'uncloud.conf'
conf_dir = os.environ.get('UCLOUD_CONF_DIR', os.path.expanduser('~/uncloud/'))
self.config_file = join_path(conf_dir, conf_name)
2019-12-21 09:36:55 +00:00
2020-01-03 13:38:59 +00:00
# this is used to cache config from etcd for 1 minutes. Without this we
# would make a lot of requests to etcd which slows down everything.
self.last_config_update = datetime.fromtimestamp(0)
self.config_parser = CustomConfigParser(allow_no_value=True)
self.config_parser.add_section('etcd')
self.config_parser.set('etcd', 'prefix', '/')
self.config_key = join_path(self['etcd']['prefix'], '/uncloud/config/')
try:
self.config_parser.read(self.config_file)
except Exception as err:
logger.error('%s', err)
2019-12-21 09:36:55 +00:00
self.read_internal_values()
2019-12-21 09:36:55 +00:00
def get_etcd_client(self):
args = tuple()
try:
kwargs = {
'host': self.config_parser.get('etcd', 'url'),
'port': self.config_parser.get('etcd', 'port'),
'ca_cert': self.config_parser.get('etcd', 'ca_cert'),
'cert_cert': self.config_parser.get('etcd', 'cert_cert'),
'cert_key': self.config_parser.get('etcd', 'cert_key'),
}
except configparser.Error as err:
raise configparser.Error(
'{} in config file {}'.format(
err.message, self.config_file
)
) from err
else:
try:
wrapper = Etcd3Wrapper(*args, **kwargs)
except Exception as err:
logger.error(
'etcd connection not successfull. Please check your config file.'
'\nDetails: %s\netcd connection parameters: %s',
err,
kwargs,
)
sys.exit(1)
else:
return wrapper
2019-12-21 09:36:55 +00:00
def read_internal_values(self):
prefix = self['etcd']['prefix']
self.config_parser.read_dict(
{
'etcd': {
'file_prefix': join_path(prefix, '/files/'),
'host_prefix': join_path(prefix, '/hosts/'),
'image_prefix': join_path(prefix, '/images/'),
'image_store_prefix': join_path(prefix, '/imagestore/'),
'network_prefix': join_path(prefix, '/networks/'),
'request_prefix': join_path(prefix, '/requests/'),
'user_prefix': join_path(prefix, '/users/'),
'vm_prefix': join_path(prefix, '/vms/'),
}
2019-12-21 09:36:55 +00:00
}
)
2019-12-21 09:36:55 +00:00
def read_config_file_values(self, config_file):
try:
# Trying to read configuration file
with open(config_file, 'r') as config_file_handle:
2019-12-21 09:36:55 +00:00
self.config_parser.read_file(config_file_handle)
except FileNotFoundError:
sys.exit(
'Configuration file {} not found!'.format(config_file)
)
2019-12-21 09:36:55 +00:00
except Exception as err:
logger.exception(err)
sys.exit('Error occurred while reading configuration file')
2019-12-21 09:36:55 +00:00
def read_values_from_etcd(self):
etcd_client = self.get_etcd_client()
2020-01-03 13:38:59 +00:00
if (datetime.utcnow() - self.last_config_update).total_seconds() > 60:
config_from_etcd = etcd_client.get(self.config_key, value_in_json=True)
if config_from_etcd:
self.config_parser.read_dict(config_from_etcd.value)
self.last_config_update = datetime.utcnow()
else:
raise KeyError('Key \'{}\' not found in etcd. Please configure uncloud.'.format(self.config_key))
2019-12-21 09:36:55 +00:00
def __getitem__(self, key):
2019-12-31 12:50:56 +00:00
# Allow failing to read from etcd if we have
# it locally
2020-01-03 13:38:59 +00:00
if key not in self.config_parser.sections():
try:
self.read_values_from_etcd()
except KeyError:
2020-01-03 13:38:59 +00:00
pass
2019-12-31 12:50:56 +00:00
2019-12-21 09:36:55 +00:00
return self.config_parser[key]
settings = Settings()