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

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. 

17 

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. 

22 

23import errno 

24import mmap 

25import os 

26import random 

27import sys 

28 

29from oslo_log import log as logging 

30from oslo_utils import excutils 

31 

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. 

35 

36LOG = logging.getLogger(__name__) 

37 

38 

39def generate_random_string(): 

40 return str(random.randint(0, sys.maxsize)) 

41 

42 

43def supports_direct_io(dirpath): 

44 

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 

48 

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) 

53 

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) 

84 

85 try: 

86 os.unlink(testfile) 

87 except Exception: 

88 pass 

89 

90 return hasDirectIO