Switch to the oslo_utils.fileutils

fileutils is graduated in the oslo.utils library.
Remove old implementation of the read_cached_file function
in the nova.utils and move from the fileutils the read_cached_file
and delete_cached_file functions to the nova.utils module and
the unit tests for these functions.

Implements: blueprint graduate-fileutils[1]
[1] https://blueprints.launchpad.net/oslo-incubator/+spec/graduate-fileutils

Depends-On: I51ba9076e1fbc16145ee2311f47b7768c16dcb20 (requirements)

Change-Id: I849f1c74ec811dbe82ba6270569a008a49eab465
changes/75/199575/12
Sergey Vilgelm 8 years ago
parent 0d696adcea
commit 741f163fc5

@ -15,6 +15,7 @@
"""Connect your vlan to the world."""
from oslo_config import cfg
from oslo_utils import fileutils
from oslo_utils import timeutils
from webob import exc
@ -26,7 +27,6 @@ from nova.compute import vm_states
from nova import exception
from nova.i18n import _
from nova import network
from nova.openstack.common import fileutils
from nova import utils
CONF = cfg.CONF

@ -15,6 +15,7 @@
"""Connect your vlan to the world."""
from oslo_config import cfg
from oslo_utils import fileutils
from oslo_utils import timeutils
from webob import exc
@ -30,7 +31,6 @@ from nova import exception
from nova.i18n import _
from nova import network
from nova import objects
from nova.openstack.common import fileutils
from nova import utils
CONF = cfg.CONF

@ -36,7 +36,6 @@ from nova.db import base
from nova import exception
from nova.i18n import _LE
from nova import objects
from nova.openstack.common import fileutils
from nova import rpc
from nova import utils
@ -484,8 +483,8 @@ class CellStateManagerFile(CellStateManager):
:param force: If True, cell status will be updated regardless
of whether it's time to do so.
"""
reloaded, data = fileutils.read_cached_file(self.cells_config_path,
force_reload=force)
reloaded, data = utils.read_cached_file(self.cells_config_path,
force_reload=force)
if reloaded:
LOG.debug("Updating cell cache from config file.")

@ -26,6 +26,7 @@ import zipfile
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import fileutils
from nova import compute
from nova.compute import flavors
@ -33,7 +34,6 @@ from nova import crypto
from nova import db
from nova import exception
from nova.i18n import _
from nova.openstack.common import fileutils
from nova import paths
from nova import utils

@ -32,6 +32,7 @@ from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import fileutils
from oslo_utils import timeutils
import paramiko
from pyasn1.codec.der import encoder as der_encoder
@ -42,7 +43,6 @@ from nova import context
from nova import db
from nova import exception
from nova.i18n import _, _LE
from nova.openstack.common import fileutils
from nova import paths
from nova import utils

@ -29,6 +29,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import excutils
from oslo_utils import fileutils
from oslo_utils import importutils
from oslo_utils import timeutils
import six
@ -36,7 +37,6 @@ import six
from nova import exception
from nova.i18n import _, _LE, _LW
from nova import objects
from nova.openstack.common import fileutils
from nova import paths
from nova.pci import utils as pci_utils
from nova import utils

@ -41,12 +41,12 @@ import urllib
from oslo_config import cfg
from oslo_log import log as logging
from oslo_log import versionutils
from oslo_utils import fileutils
import routes
import six
import webob
from nova.i18n import _LW
from nova.openstack.common import fileutils
from nova import paths
from nova import utils
from nova import wsgi

@ -1,149 +0,0 @@
# 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 contextlib
import errno
import logging
import os
import stat
import tempfile
from oslo_utils import excutils
LOG = logging.getLogger(__name__)
_FILE_CACHE = {}
DEFAULT_MODE = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO
def ensure_tree(path, mode=DEFAULT_MODE):
"""Create a directory (and any ancestor directories required)
:param path: Directory to create
:param mode: Directory creation permissions
"""
try:
os.makedirs(path, mode)
except OSError as exc:
if exc.errno == errno.EEXIST:
if not os.path.isdir(path):
raise
else:
raise
def read_cached_file(filename, force_reload=False):
"""Read from a file if it has been modified.
:param force_reload: Whether to reload the file.
:returns: A tuple with a boolean specifying if the data is fresh
or not.
"""
global _FILE_CACHE
if force_reload:
delete_cached_file(filename)
reloaded = False
mtime = os.path.getmtime(filename)
cache_info = _FILE_CACHE.setdefault(filename, {})
if not cache_info or mtime > cache_info.get('mtime', 0):
LOG.debug("Reloading cached file %s", filename)
with open(filename) as fap:
cache_info['data'] = fap.read()
cache_info['mtime'] = mtime
reloaded = True
return (reloaded, cache_info['data'])
def delete_cached_file(filename):
"""Delete cached file if present.
:param filename: filename to delete
"""
global _FILE_CACHE
if filename in _FILE_CACHE:
del _FILE_CACHE[filename]
def delete_if_exists(path, remove=os.unlink):
"""Delete a file, but ignore file not found error.
:param path: File to delete
:param remove: Optional function to remove passed path
"""
try:
remove(path)
except OSError as e:
if e.errno != errno.ENOENT:
raise
@contextlib.contextmanager
def remove_path_on_error(path, remove=delete_if_exists):
"""Protect code that wants to operate on PATH atomically.
Any exception will cause PATH to be removed.
:param path: File to work with
:param remove: Optional function to remove passed path
"""
try:
yield
except Exception:
with excutils.save_and_reraise_exception():
remove(path)
def file_open(*args, **kwargs):
"""Open file
see built-in open() documentation for more details
Note: The reason this is kept in a separate module is to easily
be able to provide a stub module that doesn't alter system
state at all (for unit tests)
"""
return open(*args, **kwargs)
def write_to_tempfile(content, path=None, suffix='', prefix='tmp'):
"""Create temporary file or use existing file.
This util is needed for creating temporary file with
specified content, suffix and prefix. If path is not None,
it will be used for writing content. If the path doesn't
exist it'll be created.
:param content: content for temporary file.
:param path: same as parameter 'dir' for mkstemp
:param suffix: same as parameter 'suffix' for mkstemp
:param prefix: same as parameter 'prefix' for mkstemp
For example: it can be used in database tests for creating
configuration files.
"""
if path:
ensure_tree(path)
(fd, path) = tempfile.mkstemp(suffix=suffix, dir=path, prefix=prefix)
try:
os.write(fd, content)
finally:
os.close(fd)
return path

@ -101,9 +101,8 @@ import six
import six.moves.urllib.parse as urlparse
import six.moves.urllib.request as urlrequest
from nova.openstack.common import fileutils
from nova.openstack.common._i18n import _, _LE
from nova import utils
policy_opts = [
cfg.StrOpt('policy_file',
@ -248,7 +247,7 @@ class Enforcer(object):
def clear(self):
"""Clears Enforcer rules, policy's cache and policy's path."""
self.set_rules({})
fileutils.delete_cached_file(self.policy_path)
utils.delete_cached_file(self.policy_path)
self.default_rule = None
self.policy_path = None
@ -287,7 +286,7 @@ class Enforcer(object):
func(os.path.join(path, policy_file), *args)
def _load_policy_file(self, path, force_reload, overwrite=True):
reloaded, data = fileutils.read_cached_file(
reloaded, data = utils.read_cached_file(
path, force_reload=force_reload)
if reloaded or not self.rules or not overwrite:
rules = Rules.load_json(data, self.default_rule)

@ -28,8 +28,8 @@ from nova import db
from nova.db.sqlalchemy import models
from nova import exception
from nova import objects
from nova.openstack.common import fileutils
from nova import test
from nova import utils
FAKE_COMPUTES = [
('host1', 1024, 100, 0, 0),
@ -114,7 +114,7 @@ class TestCellsStateManager(test.NoDBTestCase):
self.assertEqual(['no_such_file_exists.conf'], e.config_files)
@mock.patch.object(cfg.ConfigOpts, 'find_file')
@mock.patch.object(fileutils, 'read_cached_file')
@mock.patch.object(utils, 'read_cached_file')
def test_filemanager_returned(self, mock_read_cached_file, mock_find_file):
mock_find_file.return_value = "/etc/nova/cells.json"
mock_read_cached_file.return_value = (False, six.StringIO({}))

@ -25,6 +25,7 @@ from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import fileutils
from oslo_utils import timeutils
from nova import context
@ -33,7 +34,6 @@ from nova import exception
from nova.network import driver
from nova.network import linux_net
from nova import objects
from nova.openstack.common import fileutils
from nova import test
from nova import utils

@ -20,9 +20,9 @@ import tempfile
import mock
from mox3 import mox
from oslo_config import cfg
from oslo_utils import fileutils
from nova import context
from nova.openstack.common import fileutils
from nova import test
from nova.tests.unit import fake_instance
from nova import utils

@ -24,7 +24,6 @@ import tempfile
import eventlet
import mock
from mox3 import mox
import netaddr
from oslo_concurrency import processutils
from oslo_config import cfg
@ -95,35 +94,6 @@ class GenericUtilsTestCase(test.NoDBTestCase):
hostname = "<}\x1fh\x10e\x08l\x02l\x05o\x12!{>"
self.assertEqual("hello", utils.sanitize_hostname(hostname))
def test_read_cached_file(self):
self.mox.StubOutWithMock(os.path, "getmtime")
os.path.getmtime(mox.IgnoreArg()).AndReturn(1)
self.mox.ReplayAll()
cache_data = {"data": 1123, "mtime": 1}
data = utils.read_cached_file("/this/is/a/fake", cache_data)
self.assertEqual(cache_data["data"], data)
def test_read_modified_cached_file(self):
self.mox.StubOutWithMock(os.path, "getmtime")
os.path.getmtime(mox.IgnoreArg()).AndReturn(2)
self.mox.ReplayAll()
fake_contents = "lorem ipsum"
m = mock.mock_open(read_data=fake_contents)
with mock.patch("six.moves.builtins.open", m, create=True):
cache_data = {"data": 1123, "mtime": 1}
self.reload_called = False
def test_reload(reloaded_data):
self.assertEqual(reloaded_data, fake_contents)
self.reload_called = True
data = utils.read_cached_file("/this/is/a/fake", cache_data,
reload_func=test_reload)
self.assertEqual(data, fake_contents)
self.assertTrue(self.reload_called)
def test_generate_password(self):
password = utils.generate_password()
self.assertTrue([c for c in password if c in '0123456789'])
@ -235,6 +205,49 @@ class GenericUtilsTestCase(test.NoDBTestCase):
mock_method.assert_called_once_with(*expected_args)
class TestCachedFile(test.NoDBTestCase):
@mock.patch('os.path.getmtime', return_value=1)
def test_read_cached_file(self, getmtime):
utils._FILE_CACHE = {
'/this/is/a/fake': {"data": 1123, "mtime": 1}
}
fresh, data = utils.read_cached_file("/this/is/a/fake")
fdata = utils._FILE_CACHE['/this/is/a/fake']["data"]
self.assertEqual(fdata, data)
@mock.patch('os.path.getmtime', return_value=2)
def test_read_modified_cached_file(self, getmtime):
utils._FILE_CACHE = {
'/this/is/a/fake': {"data": 1123, "mtime": 1}
}
fake_contents = "lorem ipsum"
with mock.patch('six.moves.builtins.open',
mock.mock_open(read_data=fake_contents)):
fresh, data = utils.read_cached_file("/this/is/a/fake")
self.assertEqual(data, fake_contents)
self.assertTrue(fresh)
def test_delete_cached_file(self):
filename = '/this/is/a/fake/deletion/of/cached/file'
utils._FILE_CACHE = {
filename: {"data": 1123, "mtime": 1}
}
self.assertIn(filename, utils._FILE_CACHE)
utils.delete_cached_file(filename)
self.assertNotIn(filename, utils._FILE_CACHE)
def test_delete_cached_file_not_exist(self):
# We expect that if cached file does not exist no Exception raised.
filename = '/this/is/a/fake/deletion/attempt/of/not/cached/file'
self.assertNotIn(filename, utils._FILE_CACHE)
utils.delete_cached_file(filename)
self.assertNotIn(filename, utils._FILE_CACHE)
class VPNPingTestCase(test.NoDBTestCase):
"""Unit tests for utils.vpn_ping()."""
def setUp(self):

@ -24,6 +24,7 @@ import uuid
import mock
from mox3 import mox
from oslo_config import cfg
from oslo_utils import fileutils
from oslo_utils import units
import six
@ -33,7 +34,6 @@ from nova import db
from nova import exception
from nova.image import glance
from nova import objects
from nova.openstack.common import fileutils
from nova import test
from nova.tests.unit import fake_flavor
from nova.tests.unit import fake_instance

@ -39,6 +39,7 @@ from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_service import loopingcall
from oslo_utils import encodeutils
from oslo_utils import fileutils
from oslo_utils import importutils
from oslo_utils import timeutils
from oslo_utils import units
@ -59,7 +60,6 @@ from nova import db
from nova import exception
from nova.network import model as network_model
from nova import objects
from nova.openstack.common import fileutils
from nova.pci import manager as pci_manager
from nova import test
from nova.tests.unit import fake_block_device
@ -3126,7 +3126,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.disk.api.teardown_container')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver.get_info')
@mock.patch('nova.virt.disk.api.setup_container')
@mock.patch('nova.openstack.common.fileutils.ensure_tree')
@mock.patch('oslo_utils.fileutils.ensure_tree')
@mock.patch.object(fake_libvirt_utils, 'get_instance_path')
def test_unmount_fs_if_error_during_lxc_create_domain(self,
mock_get_inst_path, mock_ensure_tree, mock_setup_container,
@ -8145,7 +8145,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
drvr._hard_reboot(self.context, instance, network_info,
block_device_info)
@mock.patch('nova.openstack.common.fileutils.ensure_tree')
@mock.patch('oslo_utils.fileutils.ensure_tree')
@mock.patch('oslo_service.loopingcall.FixedIntervalLoopingCall')
@mock.patch('nova.pci.manager.get_instance_pci_devs')
@mock.patch('nova.virt.libvirt.LibvirtDriver._prepare_pci_devices_for_use')
@ -9972,7 +9972,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.disk.api.clean_lxc_namespace')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver.get_info')
@mock.patch('nova.virt.disk.api.setup_container')
@mock.patch('nova.openstack.common.fileutils.ensure_tree')
@mock.patch('oslo_utils.fileutils.ensure_tree')
@mock.patch.object(fake_libvirt_utils, 'get_instance_path')
def test_create_domain_lxc(self, mock_get_inst_path, mock_ensure_tree,
mock_setup_container, mock_get_info, mock_clean):
@ -10025,7 +10025,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver.get_info')
@mock.patch.object(fake_libvirt_utils, 'chown_for_id_maps')
@mock.patch('nova.virt.disk.api.setup_container')
@mock.patch('nova.openstack.common.fileutils.ensure_tree')
@mock.patch('oslo_utils.fileutils.ensure_tree')
@mock.patch.object(fake_libvirt_utils, 'get_instance_path')
def test_create_domain_lxc_id_maps(self, mock_get_inst_path,
mock_ensure_tree, mock_setup_container,
@ -10092,7 +10092,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch('nova.virt.disk.api.teardown_container')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver.get_info')
@mock.patch('nova.virt.disk.api.setup_container')
@mock.patch('nova.openstack.common.fileutils.ensure_tree')
@mock.patch('oslo_utils.fileutils.ensure_tree')
@mock.patch.object(fake_libvirt_utils, 'get_instance_path')
def test_create_domain_lxc_not_running(self, mock_get_inst_path,
mock_ensure_tree,

@ -18,9 +18,9 @@ import mock
import os
from oslo_concurrency import processutils
from oslo_utils import fileutils
from nova import exception
from nova.openstack.common import fileutils
from nova import test
from nova import utils
from nova.virt.libvirt import quobyte

@ -20,11 +20,11 @@ import tempfile
import mock
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_utils import fileutils
import six
from nova.compute import arch
from nova import exception
from nova.openstack.common import fileutils
from nova.storage import linuxscsi
from nova import test
from nova.tests.unit import fake_instance

@ -173,6 +173,8 @@ SM_SKIP_KEYS = (
'img_mappings', 'img_block_device_mapping',
)
_FILE_CACHE = {}
def vpn_ping(address, port, timeout=0.05, session_id=None):
"""Sends a vpn negotiation packet and returns the server session.
@ -634,27 +636,6 @@ def sanitize_hostname(hostname):
return hostname
def read_cached_file(filename, cache_info, reload_func=None):
"""Read from a file if it has been modified.
:param cache_info: dictionary to hold opaque cache.
:param reload_func: optional function to be called with data when
file is reloaded due to a modification.
:returns: data from file
"""
mtime = os.path.getmtime(filename)
if not cache_info or mtime != cache_info.get('mtime'):
LOG.debug("Reloading cached file %s", filename)
with open(filename) as fap:
cache_info['data'] = fap.read()
cache_info['mtime'] = mtime
if reload_func:
reload_func(cache_info['data'])
return cache_info['data']
@contextlib.contextmanager
def temporary_mutation(obj, **kwargs):
"""Temporarily set the attr on a particular object to a given value then
@ -1345,3 +1326,39 @@ def safe_truncate(value, length):
except UnicodeDecodeError:
b_value = b_value[:-1]
return u_value
def read_cached_file(filename, force_reload=False):
"""Read from a file if it has been modified.
:param force_reload: Whether to reload the file.
:returns: A tuple with a boolean specifying if the data is fresh
or not.
"""
global _FILE_CACHE
if force_reload:
delete_cached_file(filename)
reloaded = False
mtime = os.path.getmtime(filename)
cache_info = _FILE_CACHE.setdefault(filename, {})
if not cache_info or mtime > cache_info.get('mtime', 0):
LOG.debug("Reloading cached file %s", filename)
with open(filename) as fap:
cache_info['data'] = fap.read()
cache_info['mtime'] = mtime
reloaded = True
return (reloaded, cache_info['data'])
def delete_cached_file(filename):
"""Delete cached file if present.
:param filename: filename to delete
"""
global _FILE_CACHE
if filename in _FILE_CACHE:
del _FILE_CACHE[filename]

@ -20,12 +20,12 @@ import shutil
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import fileutils
from oslo_utils import strutils
from oslo_utils import units
from nova import exception
from nova.i18n import _LW
from nova.openstack.common import fileutils
from nova import utils
from nova import version

@ -27,6 +27,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import excutils
from oslo_utils import fileutils
from oslo_utils import importutils
from oslo_utils import units
from oslo_utils import uuidutils
@ -34,7 +35,6 @@ from oslo_utils import uuidutils
from nova.api.metadata import base as instance_metadata
from nova import exception
from nova.i18n import _, _LI, _LE, _LW
from nova.openstack.common import fileutils
from nova import utils
from nova.virt import configdrive
from nova.virt import hardware

@ -23,11 +23,11 @@ import os
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import fileutils
from nova import exception
from nova.i18n import _, _LE
from nova import image
from nova.openstack.common import fileutils
from nova.openstack.common import imageutils
from nova import utils

@ -49,6 +49,7 @@ from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_service import loopingcall
from oslo_utils import excutils
from oslo_utils import fileutils
from oslo_utils import importutils
from oslo_utils import strutils
from oslo_utils import timeutils
@ -75,7 +76,6 @@ from nova.i18n import _LW
from nova import image
from nova.network import model as network_model
from nova import objects
from nova.openstack.common import fileutils
from nova.pci import manager as pci_manager
from nova.pci import utils as pci_utils
from nova import utils

@ -24,6 +24,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import excutils
from oslo_utils import fileutils
from oslo_utils import strutils
from oslo_utils import units
import six
@ -33,7 +34,6 @@ from nova.i18n import _
from nova.i18n import _LE, _LI
from nova import image
from nova import keymgr
from nova.openstack.common import fileutils
from nova import utils
from nova.virt.disk import api as disk
from nova.virt.image import model as imgmodel

@ -30,11 +30,11 @@ from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import fileutils
from nova.i18n import _LE
from nova.i18n import _LI
from nova.i18n import _LW
from nova.openstack.common import fileutils
from nova import utils
from nova.virt import imagecache
from nova.virt.libvirt import utils as libvirt_utils

@ -17,12 +17,12 @@ import os
from oslo_concurrency import processutils
from oslo_log import log as logging
from oslo_utils import fileutils
from nova import exception as nova_exception
from nova.i18n import _
from nova.i18n import _LE
from nova.i18n import _LI
from nova.openstack.common import fileutils
from nova import utils

@ -2,7 +2,6 @@
# The list of modules to copy from oslo-incubator
module=cliutils
module=fileutils
module=imageutils
module=memorycache

Loading…
Cancel
Save