Coverage for watcher/applier/action_plan/default.py: 83%

61 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# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.com> 

5# 

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

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

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

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

15# implied. 

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

17# limitations under the License. 

18# 

19from oslo_config import cfg 

20from oslo_log import log 

21 

22from watcher.applier.action_plan import base 

23from watcher.applier import default 

24from watcher.common import exception 

25from watcher import notifications 

26from watcher import objects 

27from watcher.objects import fields 

28 

29CONF = cfg.CONF 

30LOG = log.getLogger(__name__) 

31 

32 

33class DefaultActionPlanHandler(base.BaseActionPlanHandler): 

34 

35 def __init__(self, context, service, action_plan_uuid): 

36 super(DefaultActionPlanHandler, self).__init__() 

37 self.ctx = context 

38 self.service = service 

39 self.action_plan_uuid = action_plan_uuid 

40 

41 def execute(self): 

42 try: 

43 action_plan = objects.ActionPlan.get_by_uuid( 

44 self.ctx, self.action_plan_uuid, eager=True) 

45 if action_plan.state == objects.action_plan.State.CANCELLED: 

46 self._update_action_from_pending_to_cancelled() 

47 return 

48 action_plan.hostname = CONF.host 

49 action_plan.state = objects.action_plan.State.ONGOING 

50 action_plan.save() 

51 notifications.action_plan.send_action_notification( 

52 self.ctx, action_plan, 

53 action=fields.NotificationAction.EXECUTION, 

54 phase=fields.NotificationPhase.START) 

55 

56 applier = default.DefaultApplier(self.ctx, self.service) 

57 applier.execute(self.action_plan_uuid) 

58 

59 # If any action has failed the action plan should be FAILED 

60 # Define default values for successful execution 

61 ap_state = objects.action_plan.State.SUCCEEDED 

62 notification_kwargs = { 

63 'phase': fields.NotificationPhase.END 

64 } 

65 

66 failed_filter = {'action_plan_uuid': self.action_plan_uuid, 

67 'state': objects.action.State.FAILED} 

68 failed_actions = objects.Action.list( 

69 self.ctx, filters=failed_filter, eager=True) 

70 if failed_actions: 70 ↛ 71line 70 didn't jump to line 71 because the condition on line 70 was never true

71 ap_state = objects.action_plan.State.FAILED 

72 notification_kwargs = { 

73 'phase': fields.NotificationPhase.ERROR, 

74 'priority': fields.NotificationPriority.ERROR 

75 } 

76 

77 action_plan.state = ap_state 

78 action_plan.save() 

79 notifications.action_plan.send_action_notification( 

80 self.ctx, action_plan, 

81 action=fields.NotificationAction.EXECUTION, 

82 **notification_kwargs) 

83 

84 except exception.ActionPlanCancelled as e: 

85 LOG.exception(e) 

86 action_plan.state = objects.action_plan.State.CANCELLED 

87 self._update_action_from_pending_to_cancelled() 

88 action_plan.save() 

89 notifications.action_plan.send_cancel_notification( 

90 self.ctx, action_plan, 

91 action=fields.NotificationAction.CANCEL, 

92 phase=fields.NotificationPhase.END) 

93 

94 except Exception as e: 

95 LOG.exception(e) 

96 action_plan = objects.ActionPlan.get_by_uuid( 

97 self.ctx, self.action_plan_uuid, eager=True) 

98 if action_plan.state == objects.action_plan.State.CANCELLING: 98 ↛ 99line 98 didn't jump to line 99 because the condition on line 98 was never true

99 action_plan.state = objects.action_plan.State.FAILED 

100 action_plan.save() 

101 notifications.action_plan.send_cancel_notification( 

102 self.ctx, action_plan, 

103 action=fields.NotificationAction.CANCEL, 

104 priority=fields.NotificationPriority.ERROR, 

105 phase=fields.NotificationPhase.ERROR) 

106 else: 

107 action_plan.state = objects.action_plan.State.FAILED 

108 action_plan.save() 

109 notifications.action_plan.send_action_notification( 

110 self.ctx, action_plan, 

111 action=fields.NotificationAction.EXECUTION, 

112 priority=fields.NotificationPriority.ERROR, 

113 phase=fields.NotificationPhase.ERROR) 

114 

115 def _update_action_from_pending_to_cancelled(self): 

116 filters = {'action_plan_uuid': self.action_plan_uuid, 

117 'state': objects.action.State.PENDING} 

118 actions = objects.Action.list(self.ctx, filters=filters, eager=True) 

119 if actions: 119 ↛ exitline 119 didn't return from function '_update_action_from_pending_to_cancelled' because the condition on line 119 was always true

120 for a in actions: 

121 a.state = objects.action.State.CANCELLED 

122 a.save()