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 = 13111
43 # RIC_ALARM_QUERY = 13112 # TBD
45 # Publish dict keys as constants for convenience of client code.
46 # Mixed lower/upper casing to comply with the Adapter JSON requirements.
48 KEY_MANAGED_OBJECT_ID = "managedObjectId"
49 KEY_APPLICATION_ID = "applicationId"
50 KEY_SPECIFIC_PROBLEM = "specificProblem"
51 KEY_PERCEIVED_SEVERITY = "perceivedSeverity"
52 KEY_ADDITIONAL_INFO = "additionalInfo"
53 KEY_IDENTIFYING_INFO = "identifyingInfo"
54 KEY_ALARM_ACTION = "AlarmAction"
55 KEY_ALARM_TIME = "AlarmTime"
58 class AlarmAction(Enum):
60 Action to perform at the Alarm Adapter
67 class AlarmSeverity(Enum):
80 class AlarmDetail(dict):
82 An alarm that can be raised or cleared.
86 managed_object_id: str
87 The name of the managed object that is the cause of the fault (required)
90 The name of the process that raised the alarm (required)
93 The problem that is the cause of the alarm
95 perceived_severity: AlarmSeverity
96 The severity of the alarm, a value from the enum.
99 Identifying additional information, which is part of alarm identity
102 Additional information given by the application (optional)
104 # pylint: disable=too-many-arguments
106 managed_object_id: str,
108 specific_problem: int,
109 perceived_severity: AlarmSeverity,
110 identifying_info: str,
111 additional_info: str = ""):
113 Creates an object with the specified items.
116 self[KEY_MANAGED_OBJECT_ID] = managed_object_id
117 self[KEY_APPLICATION_ID] = application_id
118 self[KEY_SPECIFIC_PROBLEM] = specific_problem
119 self[KEY_PERCEIVED_SEVERITY] = perceived_severity.name
120 self[KEY_IDENTIFYING_INFO] = identifying_info
121 self[KEY_ADDITIONAL_INFO] = additional_info
126 Provides an API for an Xapp to raise and clear alarms by sending messages
127 via RMR, which should route the messages to an Alarm Adapter.
131 vctx: ctypes c_void_p
132 Pointer to RMR context obtained by initializing RMR.
133 The context is used to allocate space and send messages.
134 The RMR routing table must have a destination for message
135 type RIC_ALARM_UPDATE as defined in this module.
137 managed_object_id: str
138 The name of the managed object that raises alarms
141 The name of the process that raises alarms
145 managed_object_id: str,
146 application_id: str):
148 Creates an alarm manager.
151 self.managed_object_id = managed_object_id
152 self.application_id = application_id
154 def create_alarm(self,
155 specific_problem: int,
156 perceived_severity: AlarmSeverity,
157 identifying_info: str,
158 additional_info: str = ""):
160 Convenience method that creates an alarm instance, an AlarmDetail object,
161 using cached values for managed object ID and application ID.
165 specific_problem: int
166 The problem that is the cause of the alarm
168 perceived_severity: AlarmSeverity
169 The severity of the alarm, a value from the enum.
171 identifying_info: str
172 Identifying additional information, which is part of alarm identity
175 Additional information given by the application (optional)
181 return AlarmDetail(managed_object_id=self.managed_object_id,
182 application_id=self.application_id,
183 specific_problem=specific_problem, perceived_severity=perceived_severity,
184 identifying_info=identifying_info, additional_info=additional_info)
187 def _create_alarm_message(alarm: AlarmDetail, action: AlarmAction):
189 Creates a dict with the specified alarm detail plus action and time.
190 Uses the current system time in milliseconds since the Epoch.
198 The action to perform at the Alarm Adapter on this alarm.
202 KEY_ALARM_ACTION: action.name,
203 KEY_ALARM_TIME: int(round(time.time() * 1000))
206 def _rmr_send_alarm(self, msg: dict):
208 Serializes the dict and sends the result via RMR using a predefined message type.
213 Dictionary with alarm message to encode and send
218 True if the send succeeded (possibly with retries), False otherwise
220 payload = json.dumps(msg).encode()
221 mdc_logger.debug("_rmr_send_alarm: payload is {}".format(payload))
222 sbuf = rmr.rmr_alloc_msg(vctx=self.vctx, size=len(payload), payload=payload,
223 mtype=RIC_ALARM_UPDATE, gen_transaction_id=True)
225 for _ in range(0, RETRIES):
226 sbuf = rmr.rmr_send_msg(self.vctx, sbuf)
227 post_send_summary = rmr.message_summary(sbuf)
228 mdc_logger.debug("_rmr_send_alarm: try {0} result is {1}".format(_, post_send_summary[rmr.RMR_MS_MSG_STATE]))
229 # stop trying if RMR does not indicate retry
230 if post_send_summary[rmr.RMR_MS_MSG_STATE] != rmr.RMR_ERR_RETRY:
233 rmr.rmr_free_msg(sbuf)
234 if post_send_summary[rmr.RMR_MS_MSG_STATE] != rmr.RMR_OK:
235 mdc_logger.warning("_rmr_send_alarm: failed after {} retries".format(RETRIES))
240 def raise_alarm(self, detail: AlarmDetail):
242 Builds and sends a message to the AlarmAdapter to raise an alarm
243 with the specified detail.
253 True if the send succeeded (possibly with retries), False otherwise
255 msg = self._create_alarm_message(detail, AlarmAction.RAISE)
256 return self._rmr_send_alarm(msg)
258 def clear_alarm(self, detail: AlarmDetail):
260 Builds and sends a message to the AlarmAdapter to clear the alarm
261 with the specified detail.
271 True if the send succeeded (possibly with retries), False otherwise
273 msg = self._create_alarm_message(detail, AlarmAction.CLEAR)
274 return self._rmr_send_alarm(msg)
276 def reraise_alarm(self, detail: AlarmDetail):
278 Builds and sends a message to the AlarmAdapter to clear the alarm with the
279 the specified detail, then builds and sends a message to raise the alarm again.
284 Alarm to clear and raise again.
289 True if the send succeeded (possibly with retries), False otherwise
291 success = self.clear_alarm(detail)
293 success = self.raise_alarm(detail)
296 def clear_all_alarms(self):
298 Builds and sends a message to the AlarmAdapter to clear all alarms.
303 True if the send succeeded (possibly with retries), False otherwise
305 detail = self.create_alarm(0, AlarmSeverity.DEFAULT, "", "")
306 msg = self._create_alarm_message(detail, AlarmAction.CLEARALL)
307 return self._rmr_send_alarm(msg)