Coverage for manila/manager.py: 87%

60 statements  

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

1# Copyright 2010 United States Government as represented by the 

2# Administrator of the National Aeronautics and Space Administration. 

3# All Rights Reserved. 

4# 

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

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

7# a copy of the License at 

8# 

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

10# 

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

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

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

14# License for the specific language governing permissions and limitations 

15# under the License. 

16 

17"""Base Manager class. 

18 

19Managers are responsible for a certain aspect of the system. It is a logical 

20grouping of code relating to a portion of the system. In general other 

21components should be using the manager to make changes to the components that 

22it is responsible for. 

23 

24For example, other components that need to deal with volumes in some way, 

25should do so by calling methods on the VolumeManager instead of directly 

26changing fields in the database. This allows us to keep all of the code 

27relating to volumes in the same place. 

28 

29We have adopted a basic strategy of Smart managers and dumb data, which means 

30rather than attaching methods to data objects, components should call manager 

31methods that act on the data. 

32 

33Methods on managers that can be executed locally should be called directly. If 

34a particular method must execute on a remote host, this should be done via rpc 

35to the service that wraps the manager 

36 

37Managers should be responsible for most of the db access, and 

38non-implementation specific data. Anything implementation specific that can't 

39be generalized should be done by the Driver. 

40 

41In general, we prefer to have one manager with multiple drivers for different 

42implementations, but sometimes it makes sense to have multiple managers. You 

43can think of it this way: Abstract different overall strategies at the manager 

44level(FlatNetwork vs VlanNetwork), and different implementations at the driver 

45level(LinuxNetDriver vs CiscoNetDriver). 

46 

47Managers will often provide methods for initial setup of a host or periodic 

48tasks to a wrapping service. 

49 

50This module provides Manager, a base class for managers. 

51 

52""" 

53 

54 

55from eventlet import greenpool 

56from oslo_config import cfg 

57from oslo_log import log 

58from oslo_service import periodic_task 

59 

60from manila.db import base 

61from manila.scheduler import rpcapi as scheduler_rpcapi 

62from manila import version 

63 

64CONF = cfg.CONF 

65LOG = log.getLogger(__name__) 

66 

67 

68class PeriodicTasks(periodic_task.PeriodicTasks): 

69 def __init__(self): 

70 super(PeriodicTasks, self).__init__(CONF) 

71 

72 

73class Manager(base.Base, PeriodicTasks): 

74 

75 @property 

76 def RPC_API_VERSION(self): 

77 """Redefine this in child classes.""" 

78 raise NotImplementedError 

79 

80 @property 

81 def target(self): 

82 """This property is used by oslo_messaging. 

83 

84 https://wiki.openstack.org/wiki/Oslo/Messaging#API_Version_Negotiation 

85 """ 

86 if not hasattr(self, '_target'): 

87 import oslo_messaging as messaging 

88 self._target = messaging.Target(version=self.RPC_API_VERSION) 

89 return self._target 

90 

91 def __init__(self, host=None, db_driver=None): 

92 if not host: 

93 host = CONF.host 

94 self.host = host 

95 self.additional_endpoints = [] 

96 self.availability_zone = CONF.storage_availability_zone 

97 super(Manager, self).__init__(db_driver) 

98 

99 def periodic_tasks(self, context, raise_on_error=False): 

100 """Tasks to be run at a periodic interval.""" 

101 return self.run_periodic_tasks(context, raise_on_error=raise_on_error) 

102 

103 def init_host(self, service_id=None): 

104 """Handle initialization if this is a standalone service. 

105 

106 A hook point for services to execute tasks before the services are made 

107 available (i.e. showing up on RPC and starting to accept RPC calls) to 

108 other components. Child classes should override this method. 

109 

110 :param service_id: ID of the service where the manager is running. 

111 """ 

112 pass 

113 

114 def init_host_with_rpc(self, service_id=None): 

115 """A hook for service to do jobs after RPC is ready. 

116 

117 Like init_host(), this method is a hook where services get a chance 

118 to execute tasks that *need* RPC. Child classes should override 

119 this method. 

120 

121 :param service_id: ID of the service where the manager is running. 

122 """ 

123 pass 

124 

125 def service_version(self, context): 

126 return version.version_string() 

127 

128 def service_config(self, context): 

129 config = {} 

130 for key in CONF: 

131 config[key] = CONF.get(key, None) 

132 return config 

133 

134 def is_service_ready(self): 

135 """Method indicating if service is ready. 

136 

137 This method should be overridden by subclasses which will return False 

138 when the back end is not ready yet. 

139 

140 """ 

141 return True 

142 

143 

144class SchedulerDependentManager(Manager): 

145 """Periodically send capability updates to the Scheduler services. 

146 

147 Services that need to update the Scheduler of their capabilities 

148 should derive from this class. Otherwise they can derive from 

149 manager.Manager directly. Updates are only sent after 

150 update_service_capabilities is called with non-None values. 

151 

152 """ 

153 

154 def __init__(self, host=None, db_driver=None, service_name='undefined'): 

155 self.last_capabilities = None 

156 self.service_name = service_name 

157 self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI() 

158 self._tp = greenpool.GreenPool() 

159 super(SchedulerDependentManager, self).__init__(host, db_driver) 

160 

161 def _add_to_threadpool(self, func, *args, **kwargs): 

162 self._tp.spawn_n(func, *args, **kwargs) 

163 

164 def update_service_capabilities(self, capabilities): 

165 """Remember these capabilities to send on next periodic update.""" 

166 self.last_capabilities = capabilities 

167 

168 @periodic_task.periodic_task 

169 def _publish_service_capabilities(self, context): 

170 """Pass data back to the scheduler at a periodic interval.""" 

171 if self.last_capabilities: 

172 LOG.debug('Notifying Schedulers of capabilities ...') 

173 self.scheduler_rpcapi.update_service_capabilities( 

174 context, 

175 self.service_name, 

176 self.host, 

177 self.last_capabilities)