Coverage for nova/privsep/utils.py: 83%
41 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Copyright 2010 United States Government as represented by the
2# Administrator of the National Aeronautics and Space Administration.
3# Copyright 2011 Justin Santa Barbara
4# Copyright 2018 Michael Still and Aptira
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
18# This module is utility methods that privsep depends on. Privsep isn't allowed
19# to depend on anything outside the privsep directory, so these need to be
20# here. That said, other parts of nova can call into these utilities if
21# needed.
23import errno
24import mmap
25import os
26import random
27import sys
29from oslo_log import log as logging
30from oslo_utils import excutils
32# NOTE(mriedem): Avoid importing nova.utils since that can cause a circular
33# import with the privsep code. In fact, avoid importing anything outside
34# of nova/privsep/ if possible.
36LOG = logging.getLogger(__name__)
39def generate_random_string():
40 return str(random.randint(0, sys.maxsize))
43def supports_direct_io(dirpath):
45 if not hasattr(os, 'O_DIRECT'): 45 ↛ 46line 45 didn't jump to line 46 because the condition on line 45 was never true
46 LOG.debug("This python runtime does not support direct I/O")
47 return False
49 # Use a random filename to avoid issues with $dirpath being on shared
50 # storage.
51 file_name = "%s.%s" % (".directio.test", generate_random_string())
52 testfile = os.path.join(dirpath, file_name)
54 hasDirectIO = True
55 fd = None
56 try:
57 fd = os.open(testfile, os.O_CREAT | os.O_WRONLY | os.O_DIRECT)
58 # Check is the write allowed with 4096 byte alignment
59 align_size = 4096
60 m = mmap.mmap(-1, align_size)
61 m.write(b"x" * align_size)
62 os.write(fd, m)
63 LOG.debug("Path '%(path)s' supports direct I/O",
64 {'path': dirpath})
65 except OSError as e:
66 if e.errno in (errno.EINVAL, errno.ENOENT): 66 ↛ 71line 66 didn't jump to line 71 because the condition on line 66 was always true
67 LOG.debug("Path '%(path)s' does not support direct I/O: "
68 "'%(ex)s'", {'path': dirpath, 'ex': e})
69 hasDirectIO = False
70 else:
71 with excutils.save_and_reraise_exception():
72 LOG.error("Error on '%(path)s' while checking "
73 "direct I/O: '%(ex)s'",
74 {'path': dirpath, 'ex': e})
75 except Exception as e:
76 with excutils.save_and_reraise_exception():
77 LOG.error("Error on '%(path)s' while checking direct I/O: "
78 "'%(ex)s'", {'path': dirpath, 'ex': e})
79 finally:
80 # ensure unlink(filepath) will actually remove the file by deleting
81 # the remaining link to it in close(fd)
82 if fd is not None:
83 os.close(fd)
85 try:
86 os.unlink(testfile)
87 except Exception:
88 pass
90 return hasDirectIO