Coverage for watcher/common/exception.py: 95%

247 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-17 12:22 +0000

1# -*- encoding: utf-8 -*- 

2# Copyright (c) 2015 b<>com 

3# 

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

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

6# You may obtain 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, 

12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 

13# implied. 

14# See the License for the specific language governing permissions and 

15# limitations under the License. 

16 

17"""Watcher base exception handling. 

18 

19Includes decorator for re-raising Watcher-type exceptions. 

20 

21SHOULD include dedicated exception logging. 

22 

23""" 

24 

25import functools 

26import sys 

27 

28from http import HTTPStatus 

29from keystoneclient import exceptions as keystone_exceptions 

30from oslo_config import cfg 

31from oslo_log import log 

32 

33from watcher._i18n import _ 

34 

35LOG = log.getLogger(__name__) 

36 

37CONF = cfg.CONF 

38 

39 

40def wrap_keystone_exception(func): 

41 """Wrap keystone exceptions and throw Watcher specific exceptions.""" 

42 @functools.wraps(func) 

43 def wrapped(*args, **kw): 

44 try: 

45 return func(*args, **kw) 

46 except keystone_exceptions.AuthorizationFailure: 

47 raise AuthorizationFailure( 

48 client=func.__name__, reason=sys.exc_info()[1]) 

49 except keystone_exceptions.ClientException: 

50 raise AuthorizationFailure( 

51 client=func.__name__, 

52 reason=(_('Unexpected keystone client error occurred: %s') 

53 % sys.exc_info()[1])) 

54 return wrapped 

55 

56 

57class WatcherException(Exception): 

58 """Base Watcher Exception 

59 

60 To correctly use this class, inherit from it and define 

61 a 'msg_fmt' property. That msg_fmt will get printf'd 

62 with the keyword arguments provided to the constructor. 

63 

64 """ 

65 msg_fmt = _("An unknown exception occurred") 

66 code = HTTPStatus.INTERNAL_SERVER_ERROR 

67 headers = {} 

68 safe = False 

69 

70 def __init__(self, message=None, **kwargs): 

71 self.kwargs = kwargs 

72 

73 if 'code' not in self.kwargs: 73 ↛ 79line 73 didn't jump to line 79 because the condition on line 73 was always true

74 try: 

75 self.kwargs['code'] = self.code 

76 except AttributeError: 

77 pass 

78 

79 if not message: 

80 try: 

81 message = self.msg_fmt % kwargs 

82 except Exception: 

83 # kwargs doesn't match a variable in msg_fmt 

84 # log the issue and the kwargs 

85 LOG.exception('Exception in string format operation') 

86 for name, value in kwargs.items(): 

87 LOG.error("%(name)s: %(value)s", 

88 {'name': name, 'value': value}) 

89 

90 if CONF.fatal_exception_format_errors: 90 ↛ 91line 90 didn't jump to line 91 because the condition on line 90 was never true

91 raise 

92 else: 

93 # at least get the core msg_fmt out if something happened 

94 message = self.msg_fmt 

95 

96 super(WatcherException, self).__init__(message) 

97 

98 def __str__(self): 

99 """Encode to utf-8 then wsme api can consume it as well""" 

100 return self.args[0] 

101 

102 def __unicode__(self): 

103 return str(self.args[0]) 

104 

105 def format_message(self): 

106 if self.__class__.__name__.endswith('_Remote'): 

107 return self.args[0] 

108 else: 

109 return str(self) 

110 

111 

112class UnsupportedError(WatcherException): 

113 msg_fmt = _("Not supported") 

114 

115 

116class NotAuthorized(WatcherException): 

117 msg_fmt = _("Not authorized") 

118 code = HTTPStatus.FORBIDDEN 

119 

120 

121class NotAcceptable(WatcherException): 

122 msg_fmt = _("Request not acceptable.") 

123 code = HTTPStatus.NOT_ACCEPTABLE 

124 

125 

126class PolicyNotAuthorized(NotAuthorized): 

127 msg_fmt = _("Policy doesn't allow %(action)s to be performed.") 

128 

129 

130class OperationNotPermitted(NotAuthorized): 

131 msg_fmt = _("Operation not permitted") 

132 

133 

134class Invalid(WatcherException, ValueError): 

135 msg_fmt = _("Unacceptable parameters") 

136 code = HTTPStatus.BAD_REQUEST 

137 

138 

139class ObjectNotFound(WatcherException): 

140 msg_fmt = _("The %(name)s %(id)s could not be found") 

141 

142 

143class Conflict(WatcherException): 

144 msg_fmt = _('Conflict') 

145 code = HTTPStatus.CONFLICT 

146 

147 

148class ResourceNotFound(ObjectNotFound): 

149 msg_fmt = _("The %(name)s resource %(id)s could not be found") 

150 code = HTTPStatus.NOT_FOUND 

151 

152 

153class InvalidParameter(Invalid): 

154 msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s") 

155 

156 

157class MissingParameter(Invalid): 

158 msg_fmt = _("%(parameter)s is required but missing. Check watcher.conf") 

159 

160 

161class InvalidIdentity(Invalid): 

162 msg_fmt = _("Expected a uuid or int but received %(identity)s") 

163 

164 

165class InvalidOperator(Invalid): 

166 msg_fmt = _("Filter operator is not valid: %(operator)s not " 

167 "in %(valid_operators)s") 

168 

169 

170class InvalidGoal(Invalid): 

171 msg_fmt = _("Goal %(goal)s is invalid") 

172 

173 

174class InvalidStrategy(Invalid): 

175 msg_fmt = _("Strategy %(strategy)s is invalid") 

176 

177 

178class InvalidAudit(Invalid): 

179 msg_fmt = _("Audit %(audit)s is invalid") 

180 

181 

182class EagerlyLoadedAuditRequired(InvalidAudit): 

183 msg_fmt = _("Audit %(audit)s was not eagerly loaded") 

184 

185 

186class InvalidActionPlan(Invalid): 

187 msg_fmt = _("Action plan %(action_plan)s is invalid") 

188 

189 

190class EagerlyLoadedActionPlanRequired(InvalidActionPlan): 

191 msg_fmt = _("Action plan %(action_plan)s was not eagerly loaded") 

192 

193 

194class EagerlyLoadedActionRequired(InvalidActionPlan): 

195 msg_fmt = _("Action %(action)s was not eagerly loaded") 

196 

197 

198class InvalidUUID(Invalid): 

199 msg_fmt = _("Expected a uuid but received %(uuid)s") 

200 

201 

202class InvalidName(Invalid): 

203 msg_fmt = _("Expected a logical name but received %(name)s") 

204 

205 

206class InvalidUuidOrName(Invalid): 

207 msg_fmt = _("Expected a logical name or uuid but received %(name)s") 

208 

209 

210class InvalidIntervalOrCron(Invalid): 

211 msg_fmt = _("Expected an interval or cron syntax but received %(name)s") 

212 

213 

214class DataModelTypeNotFound(ResourceNotFound): 

215 msg_fmt = _("The %(data_model_type)s data model could not be found") 

216 

217 

218class GoalNotFound(ResourceNotFound): 

219 msg_fmt = _("Goal %(goal)s could not be found") 

220 

221 

222class GoalAlreadyExists(Conflict): 

223 msg_fmt = _("A goal with UUID %(uuid)s already exists") 

224 

225 

226class StrategyNotFound(ResourceNotFound): 

227 msg_fmt = _("Strategy %(strategy)s could not be found") 

228 

229 

230class StrategyAlreadyExists(Conflict): 

231 msg_fmt = _("A strategy with UUID %(uuid)s already exists") 

232 

233 

234class AuditTemplateNotFound(ResourceNotFound): 

235 msg_fmt = _("AuditTemplate %(audit_template)s could not be found") 

236 

237 

238class AuditTemplateAlreadyExists(Conflict): 

239 msg_fmt = _("An audit_template with UUID or name %(audit_template)s " 

240 "already exists") 

241 

242 

243class AuditTypeNotFound(Invalid): 

244 msg_fmt = _("Audit type %(audit_type)s could not be found") 

245 

246 

247class AuditTypeNotAllowed(Invalid): 

248 msg_fmt = _("Audit type %(audit_type)s is disallowed.") 

249 

250 

251class AuditStateNotAllowed(Invalid): 

252 msg_fmt = _("Audit state %(state)s is disallowed.") 

253 

254 

255class AuditParameterNotAllowed(Invalid): 

256 msg_fmt = _("Audit parameter %(parameter)s are not allowed") 

257 

258 

259class AuditNotFound(ResourceNotFound): 

260 msg_fmt = _("Audit %(audit)s could not be found") 

261 

262 

263class AuditAlreadyExists(Conflict): 

264 msg_fmt = _("An audit with UUID or name %(audit)s already exists") 

265 

266 

267class AuditIntervalNotSpecified(Invalid): 

268 msg_fmt = _("Interval of audit must be specified for %(audit_type)s.") 

269 

270 

271class AuditIntervalNotAllowed(Invalid): 

272 msg_fmt = _("Interval of audit must not be set for %(audit_type)s.") 

273 

274 

275class AuditStartEndTimeNotAllowed(Invalid): 

276 msg_fmt = _("Start or End time of audit must not be set for " 

277 "%(audit_type)s.") 

278 

279 

280class AuditReferenced(Invalid): 

281 msg_fmt = _("Audit %(audit)s is referenced by one or multiple action " 

282 "plans") 

283 

284 

285class ActionPlanNotFound(ResourceNotFound): 

286 msg_fmt = _("ActionPlan %(action_plan)s could not be found") 

287 

288 

289class ActionPlanAlreadyExists(Conflict): 

290 msg_fmt = _("An action plan with UUID %(uuid)s already exists") 

291 

292 

293class ActionPlanReferenced(Invalid): 

294 msg_fmt = _("Action Plan %(action_plan)s is referenced by one or " 

295 "multiple actions") 

296 

297 

298class ActionPlanCancelled(WatcherException): 

299 msg_fmt = _("Action Plan with UUID %(uuid)s is cancelled by user") 

300 

301 

302class ActionPlanIsOngoing(Conflict): 

303 msg_fmt = _("Action Plan %(action_plan)s is currently running.") 

304 

305 

306class ActionNotFound(ResourceNotFound): 

307 msg_fmt = _("Action %(action)s could not be found") 

308 

309 

310class ActionAlreadyExists(Conflict): 

311 msg_fmt = _("An action with UUID %(uuid)s already exists") 

312 

313 

314class ActionReferenced(Invalid): 

315 msg_fmt = _("Action plan %(action_plan)s is referenced by one or " 

316 "multiple goals") 

317 

318 

319class ActionFilterCombinationProhibited(Invalid): 

320 msg_fmt = _("Filtering actions on both audit and action-plan is " 

321 "prohibited") 

322 

323 

324class UnsupportedActionType(UnsupportedError): 

325 msg_fmt = _("Provided %(action_type)s is not supported yet") 

326 

327 

328class EfficacyIndicatorNotFound(ResourceNotFound): 

329 msg_fmt = _("Efficacy indicator %(efficacy_indicator)s could not be found") 

330 

331 

332class EfficacyIndicatorAlreadyExists(Conflict): 

333 msg_fmt = _("An action with UUID %(uuid)s already exists") 

334 

335 

336class ScoringEngineAlreadyExists(Conflict): 

337 msg_fmt = _("A scoring engine with UUID %(uuid)s already exists") 

338 

339 

340class ScoringEngineNotFound(ResourceNotFound): 

341 msg_fmt = _("ScoringEngine %(scoring_engine)s could not be found") 

342 

343 

344class HTTPNotFound(ResourceNotFound): 

345 pass 

346 

347 

348class PatchError(Invalid): 

349 msg_fmt = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s") 

350 

351 

352class DeleteError(Invalid): 

353 msg_fmt = _("Couldn't delete when state is '%(state)s'.") 

354 

355 

356class StartError(Invalid): 

357 msg_fmt = _("Couldn't start when state is '%(state)s'.") 

358 

359 

360# decision engine 

361 

362class WorkflowExecutionException(WatcherException): 

363 msg_fmt = _('Workflow execution error: %(error)s') 

364 

365 

366class IllegalArgumentException(WatcherException): 

367 msg_fmt = _('Illegal argument') 

368 

369 

370class AuthorizationFailure(WatcherException): 

371 msg_fmt = _('%(client)s connection failed. Reason: %(reason)s') 

372 

373 

374class ClusterStateStale(WatcherException): 

375 msg_fmt = _("The cluster state is stale") 

376 

377 

378class ClusterDataModelCollectionError(WatcherException): 

379 msg_fmt = _("The cluster data model '%(cdm)s' could not be built") 

380 

381 

382class ClusterStateNotDefined(WatcherException): 

383 msg_fmt = _("The cluster state is not defined") 

384 

385 

386class NoAvailableStrategyForGoal(WatcherException): 

387 msg_fmt = _("No strategy could be found to achieve the '%(goal)s' goal.") 

388 

389 

390class InvalidIndicatorValue(WatcherException): 

391 msg_fmt = _("The indicator '%(name)s' with value '%(value)s' " 

392 "and spec type '%(spec_type)s' is invalid.") 

393 

394 

395class GlobalEfficacyComputationError(WatcherException): 

396 msg_fmt = _("Could not compute the global efficacy for the '%(goal)s' " 

397 "goal using the '%(strategy)s' strategy.") 

398 

399 

400class UnsupportedDataSource(UnsupportedError): 

401 msg_fmt = _("Datasource %(datasource)s is not supported " 

402 "by strategy %(strategy)s") 

403 

404 

405class DataSourceNotAvailable(WatcherException): 

406 msg_fmt = _("Datasource %(datasource)s is not available.") 

407 

408 

409class MetricNotAvailable(WatcherException): 

410 """Indicate that a metric is not configured or does not exists""" 

411 msg_fmt = _('Metric: %(metric)s not available') 

412 

413 

414class NoDatasourceAvailable(WatcherException): 

415 """No datasources have been configured""" 

416 msg_fmt = _('No datasources available') 

417 

418 

419class NoSuchMetricForHost(WatcherException): 

420 msg_fmt = _("No %(metric)s metric for %(host)s found.") 

421 

422 

423class ServiceAlreadyExists(Conflict): 

424 msg_fmt = _("A service with name %(name)s is already working on %(host)s.") 

425 

426 

427class ServiceNotFound(ResourceNotFound): 

428 msg_fmt = _("The service %(service)s cannot be found.") 

429 

430 

431class WildcardCharacterIsUsed(WatcherException): 

432 msg_fmt = _("You shouldn't use any other IDs of %(resource)s if you use " 

433 "wildcard character.") 

434 

435 

436class CronFormatIsInvalid(WatcherException): 

437 msg_fmt = _("Provided cron is invalid: %(message)s") 

438 

439 

440class ActionDescriptionAlreadyExists(Conflict): 

441 msg_fmt = _("An action description with type %(action_type)s is " 

442 "already exist.") 

443 

444 

445class ActionDescriptionNotFound(ResourceNotFound): 

446 msg_fmt = _("The action description %(action_id)s cannot be found.") 

447 

448 

449class ActionExecutionFailure(WatcherException): 

450 msg_fmt = _("The action %(action_id)s execution failed.") 

451 

452 

453# Model 

454 

455class ComputeResourceNotFound(WatcherException): 

456 msg_fmt = _("The compute resource '%(name)s' could not be found") 

457 

458 

459class InstanceNotFound(ComputeResourceNotFound): 

460 msg_fmt = _("The instance '%(name)s' could not be found") 

461 

462 

463class InstanceNotMapped(ComputeResourceNotFound): 

464 msg_fmt = _("The mapped compute node for instance '%(uuid)s' " 

465 "could not be found.") 

466 

467 

468class ComputeNodeNotFound(ComputeResourceNotFound): 

469 msg_fmt = _("The compute node %(name)s could not be found") 

470 

471 

472class StorageResourceNotFound(WatcherException): 

473 msg_fmt = _("The storage resource '%(name)s' could not be found") 

474 

475 

476class StorageNodeNotFound(StorageResourceNotFound): 

477 msg_fmt = _("The storage node %(name)s could not be found") 

478 

479 

480class PoolNotFound(StorageResourceNotFound): 

481 msg_fmt = _("The pool %(name)s could not be found") 

482 

483 

484class VolumeNotFound(StorageResourceNotFound): 

485 msg_fmt = _("The volume '%(name)s' could not be found") 

486 

487 

488class BaremetalResourceNotFound(WatcherException): 

489 msg_fmt = _("The baremetal resource '%(name)s' could not be found") 

490 

491 

492class IronicNodeNotFound(BaremetalResourceNotFound): 

493 msg_fmt = _("The ironic node %(uuid)s could not be found") 

494 

495 

496class LoadingError(WatcherException): 

497 msg_fmt = _("Error loading plugin '%(name)s'") 

498 

499 

500class ReservedWord(WatcherException): 

501 msg_fmt = _("The identifier '%(name)s' is a reserved word") 

502 

503 

504class NotSoftDeletedStateError(WatcherException): 

505 msg_fmt = _("The %(name)s resource %(id)s is not soft deleted") 

506 

507 

508class NegativeLimitError(WatcherException): 

509 msg_fmt = _("Limit should be positive") 

510 

511 

512class NotificationPayloadError(WatcherException): 

513 msg_fmt = _("Payload not populated when trying to send notification " 

514 "\"%(class_name)s\"") 

515 

516 

517class InvalidPoolAttributeValue(Invalid): 

518 msg_fmt = _("The %(name)s pool %(attribute)s is not integer")