Coverage for manila/api/v2/services.py: 83%

106 statements  

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

1# Copyright 2012 IBM Corp. 

2# Copyright (c) 2015 Mirantis inc. 

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 

17import http.client as http_client 

18from oslo_utils import strutils 

19import webob.exc 

20 

21from manila.api.openstack import wsgi 

22from manila.api.views import services as services_views 

23from manila import db 

24from manila import exception 

25from manila.i18n import _ 

26from manila.services import api as service_api 

27 

28 

29class ServiceMixin(object): 

30 """The Services API controller common logic. 

31 

32 Mixin class that should be inherited by Services API controllers, 

33 which are used for different API URLs and microversions. 

34 """ 

35 

36 resource_name = "service" 

37 _view_builder_class = services_views.ViewBuilder 

38 

39 @wsgi.Controller.authorize("index") 

40 def _index(self, req, support_ensure_shares=False): 

41 """Return a list of all running services.""" 

42 

43 context = req.environ['manila.context'] 

44 all_services = db.service_get_all(context) 

45 

46 services = [] 

47 for service in all_services: 

48 service_data = { 

49 'id': service['id'], 

50 'binary': service['binary'], 

51 'host': service['host'], 

52 'zone': service['availability_zone']['name'], 

53 'status': 'disabled' if service['disabled'] else 'enabled', 

54 'disabled_reason': service.get('disabled_reason'), 

55 'state': service['state'], 

56 'updated_at': service['updated_at'], 

57 } 

58 if support_ensure_shares: 58 ↛ 59line 58 didn't jump to line 59 because the condition on line 58 was never true

59 service_data['ensuring'] = service['ensuring'] 

60 services.append(service_data) 

61 

62 search_opts = [ 

63 'host', 

64 'binary', 

65 'zone', 

66 'state', 

67 'status', 

68 ] 

69 for search_opt in search_opts: 

70 if search_opt in req.GET: 

71 value = req.GET[search_opt] 

72 services = [s for s in services if s[search_opt] == value] 

73 if len(services) == 0: 73 ↛ 74line 73 didn't jump to line 74 because the condition on line 73 was never true

74 break 

75 

76 return self._view_builder.detail_list(req, services) 

77 

78 @wsgi.Controller.authorize("update") 

79 def _update(self, req, id, body, support_disabled_reason=True): 

80 """Enable/Disable scheduling for a service.""" 

81 context = req.environ['manila.context'] 

82 update_dict = {} 

83 

84 if id == "enable": 

85 data = {'disabled': False} 

86 if support_disabled_reason: 86 ↛ 87line 86 didn't jump to line 87 because the condition on line 86 was never true

87 update_dict['disabled_reason'] = None 

88 elif id == "disable": 88 ↛ 109line 88 didn't jump to line 109 because the condition on line 88 was always true

89 data = {'disabled': True} 

90 disabled_reason = body.get('disabled_reason') 

91 if disabled_reason and not support_disabled_reason: 91 ↛ 92line 91 didn't jump to line 92 because the condition on line 91 was never true

92 msg = _("'disabled_reason' option is not supported by this " 

93 "microversion. Use 2.83 or greater microversion to " 

94 "be able to set 'disabled_reason'.") 

95 raise webob.exc.HTTPBadRequest(explanation=msg) 

96 if disabled_reason: 96 ↛ 97line 96 didn't jump to line 97 because the condition on line 96 was never true

97 try: 

98 strutils.check_string_length(disabled_reason.strip(), 

99 name='disabled_reason', 

100 min_length=1, 

101 max_length=255) 

102 except (ValueError, TypeError): 

103 msg = _('Disabled reason contains invalid characters ' 

104 'or is too long') 

105 raise webob.exc.HTTPBadRequest(explanation=msg) 

106 update_dict['disabled_reason'] = disabled_reason.strip() 

107 data['disabled_reason'] = disabled_reason.strip() 

108 else: 

109 raise webob.exc.HTTPNotFound("Unknown action '%s'" % id) 

110 

111 try: 

112 data['host'] = body['host'] 

113 data['binary'] = body['binary'] 

114 except (TypeError, KeyError): 

115 raise webob.exc.HTTPBadRequest() 

116 

117 svc = db.service_get_by_args(context, data['host'], data['binary']) 

118 update_dict['disabled'] = data['disabled'] 

119 

120 db.service_update(context, svc['id'], update_dict) 

121 data['status'] = 'disabled' if id == "disable" else 'enabled' 

122 

123 return self._view_builder.summary(req, data) 

124 

125 

126class ServiceControllerLegacy(ServiceMixin, wsgi.Controller): 

127 """Deprecated Services API controller. 

128 

129 Used from microversions 2.0 to 2.6. Registered under deprecated API URL 

130 'os-services'. 

131 """ 

132 

133 @wsgi.Controller.api_version('1.0', '2.6') 

134 def index(self, req): 

135 return self._index(req) 

136 

137 @wsgi.Controller.api_version('1.0', '2.6') 

138 def update(self, req, id, body): 

139 return self._update(req, id, body, support_disabled_reason=False) 

140 

141 

142class ServiceController(ServiceMixin, wsgi.Controller): 

143 """Services API controller. 

144 

145 Used from microversion 2.7. Registered under API URL 'services'. 

146 """ 

147 

148 def __init__(self): 

149 super().__init__() 

150 self.service_api = service_api.API() 

151 

152 @wsgi.Controller.api_version('2.7', '2.85') 

153 def index(self, req): 

154 return self._index(req) 

155 

156 @wsgi.Controller.api_version('2.86') # noqa 

157 def index(self, req): # pylint: disable=function-redefined # noqa F811 

158 return self._index(req, support_ensure_shares=True) 

159 

160 @wsgi.Controller.api_version('2.7', '2.82') 

161 def update(self, req, id, body): 

162 return self._update(req, id, body, support_disabled_reason=False) 

163 

164 @wsgi.Controller.api_version('2.83') # noqa 

165 def update(self, req, id, body): # pylint: disable=function-redefined # noqa F811 

166 return self._update(req, id, body) 

167 

168 @wsgi.Controller.api_version('2.86') 

169 @wsgi.Controller.authorize 

170 def ensure_shares(self, req, body): 

171 """Starts ensure shares for a given manila-share binary.""" 

172 context = req.environ['manila.context'] 

173 

174 host = body.get('host', None) 

175 if not host: 

176 raise webob.exc.HTTPBadRequest('Missing host parameter.') 

177 

178 try: 

179 # The only binary supported is Manila share. 

180 service = db.service_get_by_args(context, host, 'manila-share') 

181 except exception.NotFound: 

182 raise webob.exc.HTTPNotFound( 

183 "manila-share binary for '%s' host not found" % id 

184 ) 

185 

186 try: 

187 self.service_api.ensure_shares(context, service, host) 

188 except webob.exc.HTTPConflict: 

189 raise 

190 

191 return webob.Response(status_int=http_client.ACCEPTED) 

192 

193 

194def create_resource_legacy(): 

195 return wsgi.Resource(ServiceControllerLegacy()) 

196 

197 

198def create_resource(): 

199 return wsgi.Resource(ServiceController())