Coverage for manila/scheduler/scheduler_options.py: 88%

48 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright (c) 2011 OpenStack, LLC. 

2# All Rights Reserved. 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); you may 

5# not use this file except in compliance with the License. You may obtain 

6# a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

13# License for the specific language governing permissions and limitations 

14# under the License. 

15 

16""" 

17SchedulerOptions monitors a local .json file for changes and loads 

18it if needed. This file is converted to a data structure and passed 

19into the filtering and weighing functions which can use it for 

20dynamic configuration. 

21""" 

22 

23import datetime 

24import os 

25 

26from oslo_config import cfg 

27from oslo_log import log 

28from oslo_serialization import jsonutils 

29from oslo_utils import timeutils 

30 

31scheduler_json_config_location_opt = cfg.StrOpt( 

32 'scheduler_json_config_location', 

33 default='', 

34 help='Absolute path to scheduler configuration JSON file.') 

35 

36CONF = cfg.CONF 

37CONF.register_opt(scheduler_json_config_location_opt) 

38 

39LOG = log.getLogger(__name__) 

40 

41 

42class SchedulerOptions(object): 

43 """Monitor and load local .json file for filtering and weighing. 

44 

45 SchedulerOptions monitors a local .json file for changes and loads it 

46 if needed. This file is converted to a data structure and passed into 

47 the filtering and weighing functions which can use it for dynamic 

48 configuration. 

49 """ 

50 

51 def __init__(self): 

52 super(SchedulerOptions, self).__init__() 

53 self.data = {} 

54 self.last_modified = None 

55 self.last_checked = None 

56 

57 def _get_file_handle(self, filename): 

58 """Get file handle. Broken out for testing.""" 

59 return open(filename) 

60 

61 def _get_file_timestamp(self, filename): 

62 """Get the last modified datetime. Broken out for testing.""" 

63 try: 

64 return os.path.getmtime(filename) 

65 except os.error: 

66 LOG.exception("Could not stat scheduler options file " 

67 "%(filename)s.", 

68 {"filename": filename}) 

69 raise 

70 

71 def _load_file(self, handle): 

72 """Decode the JSON file. Broken out for testing.""" 

73 try: 

74 return jsonutils.load(handle) 

75 except ValueError: 

76 LOG.exception("Could not decode scheduler options.") 

77 return {} 

78 

79 def _get_time_now(self): 

80 """Get current UTC. Broken out for testing.""" 

81 return timeutils.utcnow() 

82 

83 def get_configuration(self, filename=None): 

84 """Check the json file for changes and load it if needed.""" 

85 if not filename: 

86 filename = CONF.scheduler_json_config_location 

87 if not filename: 

88 return self.data 

89 if self.last_checked: 

90 now = self._get_time_now() 

91 if now - self.last_checked < datetime.timedelta(minutes=5): 

92 return self.data 

93 

94 last_modified = self._get_file_timestamp(filename) 

95 if (not last_modified or not self.last_modified or 

96 last_modified > self.last_modified): 

97 self.data = self._load_file(self._get_file_handle(filename)) 

98 self.last_modified = last_modified 

99 if not self.data: 

100 self.data = {} 

101 

102 return self.data