oslo.policy/oslo_policy/_cache_handler.py
BubaVV 9919f1317c Correctly handle IO errors at policy file load
For now, policy file unaccessible due to access permission leads to
silent failure without any notifictaion. Side effects of it are also
affected by policy caching and might be quite confusing, like periodic
disappearing of Horizon panels. Proposed patch added handling of such
errors.

Closes-bug: #1836390
Change-Id: I0d67b6e7c2dcaa63d6bb807f013e5e7334efc715
2021-02-09 14:32:07 +00:00

82 lines
2.6 KiB
Python

# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import errno
import logging
import os
from oslo_config import cfg
LOG = logging.getLogger(__name__)
def read_cached_file(cache, filename, force_reload=False):
"""Read from a file if it has been modified.
:param cache: dictionary to hold opaque cache.
:param filename: the file path to read.
:param force_reload: Whether to reload the file.
:returns: A tuple with a boolean specifying if the data is fresh
or not.
"""
if force_reload:
delete_cached_file(cache, filename)
reloaded = False
try:
mtime = os.path.getmtime(filename)
except OSError as err:
msg = err.strerror
LOG.error('Config file not found %(filename)s: %(msg)s',
{'filename': filename, 'msg': msg})
return True, {}
cache_info = cache.setdefault(filename, {})
if not cache_info or mtime > cache_info.get('mtime', 0):
LOG.debug("Reloading cached file %s", filename)
try:
with open(filename) as fap:
cache_info['data'] = fap.read()
except IOError as err:
msg = err.strerror
err_code = err.errno
LOG.error('IO error loading %(filename)s: %(msg)s',
{'filename': filename, 'msg': msg})
if err_code == errno.EACCES:
raise cfg.ConfigFilesPermissionDeniedError((filename,))
except OSError as err:
msg = err.strerror
LOG.error('Config file not found %(filename)s: %(msg)s',
{'filename': filename, 'msg': msg})
raise cfg.ConfigFilesNotFoundError((filename,))
cache_info['mtime'] = mtime
reloaded = True
return (reloaded, cache_info['data'])
def delete_cached_file(cache, filename):
"""Delete cached file if present.
:param cache: dictionary to hold opaque cache.
:param filename: filename to delete
"""
try:
del cache[filename]
except KeyError:
pass