1 # ==================================================================================
2 # Copyright (c) 2020 AT&T Intellectual Property.
3 # Copyright (c) 2020 Nokia
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 # ==================================================================================
18 Provides classes and methods to define, raise, reraise and clear alarms.
19 All actions are implemented by sending RMR messages to the Alarm Adapter
20 that comply with the JSON schema in file alarm-schema.json.
23 from ctypes import c_void_p
24 from enum import Enum, auto
27 from mdclogpy import Logger
28 from ricxappframe.rmr import rmr
34 mdc_logger = Logger(name=__name__)
42 RIC_ALARM_UPDATE = 110
44 # Publish dict keys as constants for convenience of client code.
45 # Mixed lower/upper casing to comply with the Adapter JSON requirements.
47 KEY_MANAGED_OBJECT_ID = "managedObjectId"
48 KEY_APPLICATION_ID = "applicationId"
49 KEY_SPECIFIC_PROBLEM = "specificProblem"
50 KEY_PERCEIVED_SEVERITY = "perceivedSeverity"
51 KEY_ADDITIONAL_INFO = "additionalInfo"
52 KEY_IDENTIFYING_INFO = "identifyingInfo"
53 KEY_ALARM_ACTION = "AlarmAction"
54 KEY_ALARM_TIME = "AlarmTime"
57 class AlarmAction(Enum):
59 Action to perform at the Alarm Adapter
66 class AlarmSeverity(Enum):
79 class AlarmDetail(dict):
81 An alarm that can be raised or cleared.
85 managed_object_id: str
86 The name of the managed object that is the cause of the fault (required)
89 The name of the process that raised the alarm (required)
92 The problem that is the cause of the alarm
94 perceived_severity: AlarmSeverity
95 The severity of the alarm, a value from the enum.
98 Identifying additional information, which is part of alarm identity
101 Additional information given by the application (optional)
103 # pylint: disable=too-many-arguments
105 managed_object_id: str,
107 specific_problem: int,
108 perceived_severity: AlarmSeverity,
109 identifying_info: str,
110 additional_info: str = ""):
112 Creates an object with the specified items.
115 self[KEY_MANAGED_OBJECT_ID] = managed_object_id
116 self[KEY_APPLICATION_ID] = application_id
117 self[KEY_SPECIFIC_PROBLEM] = specific_problem
118 self[KEY_PERCEIVED_SEVERITY] = perceived_severity.name
119 self[KEY_IDENTIFYING_INFO] = identifying_info
120 self[KEY_ADDITIONAL_INFO] = additional_info
125 Provides an API for an Xapp to raise and clear alarms by sending messages
126 via RMR, which should route the messages to an Alarm Adapter.
130 vctx: ctypes c_void_p
131 Pointer to RMR context obtained by initializing RMR.
132 The context is used to allocate space and send messages.
133 The RMR routing table must have a destination for message
134 type RIC_ALARM_UPDATE as defined in this module.
136 managed_object_id: str
137 The name of the managed object that raises alarms
140 The name of the process that raises alarms
144 managed_object_id: str,
145 application_id: str):
147 Creates an alarm manager.
150 self.managed_object_id = managed_object_id
151 self.application_id = application_id
153 def create_alarm(self,
154 specific_problem: int,
155 perceived_severity: AlarmSeverity,
156 identifying_info: str,
157 additional_info: str = ""):
159 Convenience method that creates an alarm instance, an AlarmDetail object,
160 using cached values for managed object ID and application ID.
164 specific_problem: int
165 The problem that is the cause of the alarm
167 perceived_severity: AlarmSeverity
168 The severity of the alarm, a value from the enum.
170 identifying_info: str
171 Identifying additional information, which is part of alarm identity
174 Additional information given by the application (optional)
180 return AlarmDetail(managed_object_id=self.managed_object_id,
181 application_id=self.application_id,
182 specific_problem=specific_problem, perceived_severity=perceived_severity,
183 identifying_info=identifying_info, additional_info=additional_info)
186 def _create_alarm_message(alarm: AlarmDetail, action: AlarmAction):
188 Creates a dict with the specified alarm detail plus action and time.
189 Uses the current system time in milliseconds since the Epoch.
197 The action to perform at the Alarm Adapter on this alarm.
201 KEY_ALARM_ACTION: action.name,
202 KEY_ALARM_TIME: int(round(time.time() * 1000))
205 def _rmr_send_alarm(self, msg: dict):
207 Serializes the dict and sends the result via RMR using a predefined message type.
212 Dictionary with alarm message to encode and send
217 True if the send succeeded (possibly with retries), False otherwise
219 payload = json.dumps(msg).encode()
220 mdc_logger.debug("_rmr_send_alarm: payload is {}".format(payload))
221 sbuf = rmr.rmr_alloc_msg(vctx=self.vctx, size=len(payload), payload=payload,
222 mtype=RIC_ALARM_UPDATE, gen_transaction_id=True)
224 for _ in range(0, RETRIES):
225 sbuf = rmr.rmr_send_msg(self.vctx, sbuf)
226 post_send_summary = rmr.message_summary(sbuf)
227 mdc_logger.debug("_rmr_send_alarm: try {0} result is {1}".format(_, post_send_summary[rmr.RMR_MS_MSG_STATE]))
228 # stop trying if RMR does not indicate retry
229 if post_send_summary[rmr.RMR_MS_MSG_STATE] != rmr.RMR_ERR_RETRY:
232 rmr.rmr_free_msg(sbuf)
233 if post_send_summary[rmr.RMR_MS_MSG_STATE] != rmr.RMR_OK:
234 mdc_logger.warning("_rmr_send_alarm: failed after {} retries".format(RETRIES))
239 def raise_alarm(self, detail: AlarmDetail):
241 Builds and sends a message to the AlarmAdapter to raise an alarm
242 with the specified detail.
252 True if the send succeeded (possibly with retries), False otherwise
254 msg = self._create_alarm_message(detail, AlarmAction.RAISE)
255 return self._rmr_send_alarm(msg)
257 def clear_alarm(self, detail: AlarmDetail):
259 Builds and sends a message to the AlarmAdapter to clear the alarm
260 with the specified detail.
270 True if the send succeeded (possibly with retries), False otherwise
272 msg = self._create_alarm_message(detail, AlarmAction.CLEAR)
273 return self._rmr_send_alarm(msg)
275 def reraise_alarm(self, detail: AlarmDetail):
277 Builds and sends a message to the AlarmAdapter to clear the alarm with the
278 the specified detail, then builds and sends a message to raise the alarm again.
283 Alarm to clear and raise again.
288 True if the send succeeded (possibly with retries), False otherwise
290 success = self.clear_alarm(detail)
292 success = self.raise_alarm(detail)
295 def clear_all_alarms(self):
297 Builds and sends a message to the AlarmAdapter to clear all alarms.
302 True if the send succeeded (possibly with retries), False otherwise
304 detail = self.create_alarm(0, AlarmSeverity.DEFAULT, "", "")
305 msg = self._create_alarm_message(detail, AlarmAction.CLEARALL)
306 return self._rmr_send_alarm(msg)