More code refactoring
[ric-plt/alarm-go.git] / manager / cmd / manager.go
1 /*
2  *  Copyright (c) 2020 AT&T Intellectual Property.
3  *  Copyright (c) 2020 Nokia.
4  *
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
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,
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  *
17  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
18  * platform project (RICP).
19  */
20
21 package main
22
23 import (
24         "bytes"
25         "encoding/json"
26         "fmt"
27         "io/ioutil"
28         "net/http"
29         "os"
30         "time"
31
32         "gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
33         app "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
34         clientruntime "github.com/go-openapi/runtime/client"
35         "github.com/go-openapi/strfmt"
36         "github.com/prometheus/alertmanager/api/v2/client"
37         "github.com/prometheus/alertmanager/api/v2/client/alert"
38         "github.com/prometheus/alertmanager/api/v2/models"
39         "github.com/spf13/viper"
40 )
41
42 func (a *AlarmManager) StartAlertTimer() {
43         tick := time.Tick(time.Duration(a.alertInterval) * time.Millisecond)
44         for range tick {
45                 a.mutex.Lock()
46                 for _, m := range a.activeAlarms {
47                         app.Logger.Info("Re-raising alarm: %v", m)
48                         a.PostAlert(a.GenerateAlertLabels(m.Alarm, AlertStatusActive, m.AlarmTime))
49                 }
50                 a.mutex.Unlock()
51         }
52 }
53
54 func (a *AlarmManager) Consume(rp *app.RMRParams) (err error) {
55         app.Logger.Info("Message received!")
56
57         defer app.Rmr.Free(rp.Mbuf)
58         switch rp.Mtype {
59         case alarm.RIC_ALARM_UPDATE:
60                 a.HandleAlarms(rp)
61         default:
62                 app.Logger.Info("Unknown Message Type '%d', discarding", rp.Mtype)
63         }
64
65         return nil
66 }
67
68 func (a *AlarmManager) HandleAlarms(rp *app.RMRParams) (*alert.PostAlertsOK, error) {
69         var m alarm.AlarmMessage
70         app.Logger.Info("Received JSON: %s", rp.Payload)
71         if err := json.Unmarshal(rp.Payload, &m); err != nil {
72                 app.Logger.Error("json.Unmarshal failed: %v", err)
73                 return nil, err
74         }
75         app.Logger.Info("newAlarm: %v", m)
76
77         return a.ProcessAlarm(&AlarmNotification{m, alarm.AlarmDefinition{}})
78 }
79
80 func (a *AlarmManager) ProcessAlarm(m *AlarmNotification) (*alert.PostAlertsOK, error) {
81         a.mutex.Lock()
82         alarmDef := &alarm.AlarmDefinition{}
83         var ok bool
84         if alarmDef, ok = alarm.RICAlarmDefinitions[m.Alarm.SpecificProblem]; !ok {
85                 app.Logger.Warn("Alarm (SP='%d') not recognized, suppressing ...", m.Alarm.SpecificProblem)
86                 a.mutex.Unlock()
87                 return nil, nil
88         }
89
90         idx, found := a.IsMatchFound(m.Alarm)
91         // Suppress duplicate alarms
92         if found && m.AlarmAction == alarm.AlarmActionRaise {
93                 app.Logger.Info("Duplicate alarm found, suppressing ...")
94                 if m.PerceivedSeverity == a.activeAlarms[idx].PerceivedSeverity {
95                         // Duplicate with same severity found
96                         a.mutex.Unlock()
97                         return nil, nil
98                 } else {
99                         // Remove duplicate with different severity
100                         a.activeAlarms = a.RemoveAlarm(a.activeAlarms, idx, "active")
101                 }
102         }
103
104         // Clear alarm if found from active alarm list
105         if found && m.AlarmAction == alarm.AlarmActionClear {
106                 return a.ProcessClearAlarm(m, alarmDef, idx)
107         }
108
109         // New alarm -> update active alarms and post to Alert Manager
110         if m.AlarmAction == alarm.AlarmActionRaise {
111                 return a.ProcessRaiseAlarm(m, alarmDef)
112         }
113
114         a.mutex.Unlock()
115         return nil, nil
116 }
117
118 func (a *AlarmManager) ProcessRaiseAlarm(m *AlarmNotification, alarmDef *alarm.AlarmDefinition) (*alert.PostAlertsOK, error) {
119         app.Logger.Debug("Raise alarmDef.RaiseDelay = %v, AlarmNotification = %v", alarmDef.RaiseDelay, *m)
120
121         // RaiseDelay > 0 in an alarm object in active alarm table indicates that raise delay is still ongoing for the alarm
122         m.AlarmDefinition.RaiseDelay = alarmDef.RaiseDelay
123         a.UpdateAlarmFields(a.GenerateAlarmId(), m)
124         a.UpdateActiveAlarmList(m)
125         a.mutex.Unlock()
126
127         if alarmDef.RaiseDelay > 0 {
128                 timerDelay(alarmDef.RaiseDelay)
129                 a.mutex.Lock()
130                 // Alarm may have been deleted from active alarms table during delay or table index may have changed
131                 idx, found := a.IsMatchFound(m.Alarm)
132                 if found {
133                         // Alarm is not showed in active alarms or alarm history via CLI before RaiseDelay has elapsed, i.e the value is 0
134                         a.activeAlarms[idx].AlarmDefinition.RaiseDelay = 0
135                         app.Logger.Debug("Raise after delay alarmDef.RaiseDelay = %v, AlarmNotification = %v", alarmDef.RaiseDelay, *m)
136                         a.mutex.Unlock()
137                 } else {
138                         app.Logger.Debug("Alarm deleted during raise delay. AlarmNotification = %v", *m)
139                         a.mutex.Unlock()
140                         return nil, nil
141                 }
142         }
143
144         m.AlarmDefinition.RaiseDelay = 0
145         a.UpdateAlarmHistoryList(m)
146         a.WriteAlarmInfoToPersistentVolume()
147
148         // Send alarm notification to NOMA, if enabled
149         if app.Config.GetBool("controls.noma.enabled") {
150                 return a.PostAlarm(m)
151         }
152         return a.PostAlert(a.GenerateAlertLabels(m.Alarm, AlertStatusActive, m.AlarmTime))
153 }
154
155 func (a *AlarmManager) ProcessClearAlarm(m *AlarmNotification, alarmDef *alarm.AlarmDefinition, idx int) (*alert.PostAlertsOK, error) {
156         app.Logger.Debug("Clear alarmDef.ClearDelay = %v, AlarmNotification = %v", alarmDef.ClearDelay, *m)
157         if alarmDef.ClearDelay > 0 {
158                 a.mutex.Unlock()
159                 timerDelay(alarmDef.ClearDelay)
160                 app.Logger.Debug("Clear after delay alarmDef.ClearDelay = %v, AlarmNotification = %v", alarmDef.ClearDelay, *m)
161                 a.mutex.Lock()
162                 // Another alarm clear may have happened during delay and active alarms table index changed
163                 var found bool
164                 idx, found = a.IsMatchFound(m.Alarm)
165                 if !found {
166                         a.mutex.Unlock()
167                         return nil, nil
168                 }
169         }
170         a.UpdateAlarmFields(a.activeAlarms[idx].AlarmId, m)
171         a.alarmHistory = append(a.alarmHistory, *m)
172         a.activeAlarms = a.RemoveAlarm(a.activeAlarms, idx, "active")
173         if (len(a.alarmHistory) >= a.maxAlarmHistory) && (a.exceededAlarmHistoryOn == false) {
174                 app.Logger.Warn("alarm history count exceeded maxAlarmHistory threshold")
175                 a.GenerateThresholdAlarm(alarm.ALARM_HISTORY_EXCEED_MAX_THRESHOLD, "history")
176         }
177
178         if a.exceededActiveAlarmOn && m.Alarm.SpecificProblem == alarm.ACTIVE_ALARM_EXCEED_MAX_THRESHOLD {
179                 a.exceededActiveAlarmOn = false
180         }
181
182         if a.exceededAlarmHistoryOn && m.Alarm.SpecificProblem == alarm.ALARM_HISTORY_EXCEED_MAX_THRESHOLD {
183                 a.exceededAlarmHistoryOn = false
184         }
185         a.WriteAlarmInfoToPersistentVolume()
186
187         a.mutex.Unlock()
188         if a.postClear && app.Config.GetBool("controls.noma.enabled") {
189                 m.PerceivedSeverity = alarm.SeverityCleared
190                 return a.PostAlarm(m)
191         }
192         return nil, nil
193 }
194
195 func timerDelay(delay int) {
196         timer := time.NewTimer(time.Duration(delay) * time.Second)
197         <-timer.C
198 }
199
200 func (a *AlarmManager) IsMatchFound(newAlarm alarm.Alarm) (int, bool) {
201         for i, m := range a.activeAlarms {
202                 if m.ManagedObjectId == newAlarm.ManagedObjectId && m.ApplicationId == newAlarm.ApplicationId &&
203                         m.SpecificProblem == newAlarm.SpecificProblem && m.IdentifyingInfo == newAlarm.IdentifyingInfo {
204                         return i, true
205                 }
206         }
207         return -1, false
208 }
209
210 func (a *AlarmManager) RemoveAlarm(alarms []AlarmNotification, i int, listName string) []AlarmNotification {
211         app.Logger.Info("Alarm '%+v' deleted from the '%s' list", alarms[i], listName)
212         copy(alarms[i:], alarms[i+1:])
213         return alarms[:len(alarms)-1]
214 }
215
216 func (a *AlarmManager) GenerateAlarmId() int {
217         a.uniqueAlarmId++ // @todo: generate a unique ID
218         return a.uniqueAlarmId
219 }
220
221 func (a *AlarmManager) UpdateAlarmFields(alarmId int, newAlarm *AlarmNotification) {
222         alarmDef := alarm.RICAlarmDefinitions[newAlarm.SpecificProblem]
223         newAlarm.AlarmId = alarmId
224         newAlarm.AlarmText = alarmDef.AlarmText
225         newAlarm.EventType = alarmDef.EventType
226 }
227
228 func (a *AlarmManager) GenerateThresholdAlarm(sp int, data string) bool {
229         thresholdAlarm := a.alarmClient.NewAlarm(sp, alarm.SeverityWarning, "threshold", data)
230         thresholdMessage := alarm.AlarmMessage{
231                 Alarm:       thresholdAlarm,
232                 AlarmAction: alarm.AlarmActionRaise,
233                 AlarmTime:   (time.Now().UnixNano()),
234         }
235         alarmDef := alarm.RICAlarmDefinitions[sp]
236         alarmId := a.GenerateAlarmId()
237         alarmDef.AlarmId = alarmId
238         a.activeAlarms = append(a.activeAlarms, AlarmNotification{thresholdMessage, *alarmDef})
239         a.alarmHistory = append(a.alarmHistory, AlarmNotification{thresholdMessage, *alarmDef})
240
241         return true
242 }
243
244 func (a *AlarmManager) UpdateActiveAlarmList(newAlarm *AlarmNotification) {
245         /* If maximum number of active alarms is reached, an error log writing is made, and new alarm indicating the problem is raised.
246            The attempt to raise the alarm next time will be suppressed when found as duplicate. */
247         if (len(a.activeAlarms) >= a.maxActiveAlarms) && (a.exceededActiveAlarmOn == false) {
248                 app.Logger.Warn("active alarm count exceeded maxActiveAlarms threshold")
249                 a.exceededActiveAlarmOn = a.GenerateThresholdAlarm(alarm.ACTIVE_ALARM_EXCEED_MAX_THRESHOLD, "active")
250         }
251
252         // @todo: For now just keep the  active alarms in-memory. Use SDL later for persistence
253         a.activeAlarms = append(a.activeAlarms, *newAlarm)
254 }
255
256 func (a *AlarmManager) UpdateAlarmHistoryList(newAlarm *AlarmNotification) {
257         /* If maximum number of events in alarm history is reached, an error log writing is made,
258            and new alarm indicating the problem is raised. The attempt to add new event time will
259            be suppressed */
260
261         if (len(a.alarmHistory) >= a.maxAlarmHistory) && (a.exceededAlarmHistoryOn == false) {
262                 app.Logger.Warn("alarm history count exceeded maxAlarmHistory threshold")
263                 a.exceededAlarmHistoryOn = a.GenerateThresholdAlarm(alarm.ALARM_HISTORY_EXCEED_MAX_THRESHOLD, "history")
264         }
265
266         // @todo: For now just keep the alarms history in-memory. Use SDL later for persistence
267         a.alarmHistory = append(a.alarmHistory, *newAlarm)
268 }
269
270 func (a *AlarmManager) PostAlarm(m *AlarmNotification) (*alert.PostAlertsOK, error) {
271         result, err := json.Marshal(m)
272         if err != nil {
273                 app.Logger.Info("json.Marshal failed: %v", err)
274                 return nil, err
275         }
276
277         fullUrl := fmt.Sprintf("%s/%s", app.Config.GetString("controls.noma.host"), app.Config.GetString("controls.noma.alarmUrl"))
278         app.Logger.Info("Posting alarm to '%s'", fullUrl)
279
280         resp, err := http.Post(fullUrl, "application/json", bytes.NewReader(result))
281         if err != nil || resp == nil {
282                 app.Logger.Info("Unable to post alarm to '%s': %v", fullUrl, err)
283         }
284
285         return nil, err
286 }
287
288 func (a *AlarmManager) GenerateAlertLabels(newAlarm alarm.Alarm, status AlertStatus, alarmTime int64) (models.LabelSet, models.LabelSet) {
289         alarmDef := alarm.RICAlarmDefinitions[newAlarm.SpecificProblem]
290         amLabels := models.LabelSet{
291                 "status":      string(status),
292                 "alertname":   alarmDef.AlarmText,
293                 "severity":    string(newAlarm.PerceivedSeverity),
294                 "service":     fmt.Sprintf("%s/%s", newAlarm.ManagedObjectId, newAlarm.ApplicationId),
295                 "system_name": "RIC",
296         }
297         amAnnotations := models.LabelSet{
298                 "alarm_id":         fmt.Sprintf("%d", alarmDef.AlarmId),
299                 "specific_problem": fmt.Sprintf("%d", newAlarm.SpecificProblem),
300                 "event_type":       alarmDef.EventType,
301                 "identifying_info": newAlarm.IdentifyingInfo,
302                 "additional_info":  newAlarm.AdditionalInfo,
303                 "description":      fmt.Sprintf("%s:%s", newAlarm.IdentifyingInfo, newAlarm.AdditionalInfo),
304                 "instructions":     alarmDef.OperationInstructions,
305                 "timestamp":        fmt.Sprintf("%s", time.Unix(0, alarmTime).Format("02/01/2006, 15:04:05")),
306         }
307
308         return amLabels, amAnnotations
309 }
310
311 func (a *AlarmManager) NewAlertmanagerClient() *client.Alertmanager {
312         cr := clientruntime.New(a.amHost, a.amBaseUrl, a.amSchemes)
313         return client.New(cr, strfmt.Default)
314 }
315
316 func (a *AlarmManager) PostAlert(amLabels, amAnnotations models.LabelSet) (*alert.PostAlertsOK, error) {
317         pa := &models.PostableAlert{
318                 Alert: models.Alert{
319                         GeneratorURL: strfmt.URI(""),
320                         Labels:       amLabels,
321                 },
322                 Annotations: amAnnotations,
323         }
324         alertParams := alert.NewPostAlertsParams().WithAlerts(models.PostableAlerts{pa})
325
326         app.Logger.Info("Posting alerts: labels: %+v, annotations: %+v", amLabels, amAnnotations)
327         ok, err := a.NewAlertmanagerClient().Alert.PostAlerts(alertParams)
328         if err != nil {
329                 app.Logger.Error("Posting alerts to '%s/%s' failed with error: %v", a.amHost, a.amBaseUrl, err)
330         }
331         return ok, err
332 }
333
334 func (a *AlarmManager) StatusCB() bool {
335         if !a.rmrReady {
336                 app.Logger.Info("RMR not ready yet!")
337         }
338
339         return a.rmrReady
340 }
341
342 func (a *AlarmManager) ConfigChangeCB(configparam string) {
343
344         a.maxActiveAlarms = app.Config.GetInt("controls.maxActiveAlarms")
345         a.maxAlarmHistory = app.Config.GetInt("controls.maxAlarmHistory")
346         a.alertInterval = viper.GetInt("controls.promAlertManager.alertInterval")
347         a.amHost = viper.GetString("controls.promAlertManager.address")
348
349         app.Logger.Debug("ConfigChangeCB: maxActiveAlarms %v", a.maxActiveAlarms)
350         app.Logger.Debug("ConfigChangeCB: maxAlarmHistory = %v", a.maxAlarmHistory)
351         app.Logger.Debug("ConfigChangeCB: alertInterval %v", a.alertInterval)
352         app.Logger.Debug("ConfigChangeCB: amHost = %v", a.amHost)
353
354         return
355 }
356
357 func (a *AlarmManager) ReadAlarmDefinitionFromJson() {
358
359         filename := os.Getenv("DEF_FILE")
360         file, err := ioutil.ReadFile(filename)
361         if err == nil {
362                 data := RicAlarmDefinitions{}
363                 err = json.Unmarshal([]byte(file), &data)
364                 if err == nil {
365                         for _, alarmDefinition := range data.AlarmDefinitions {
366                                 _, exists := alarm.RICAlarmDefinitions[alarmDefinition.AlarmId]
367                                 if exists {
368                                         app.Logger.Error("ReadAlarmDefinitionFromJson: alarm definition already exists for %v", alarmDefinition.AlarmId)
369                                 } else {
370                                         app.Logger.Debug("ReadAlarmDefinitionFromJson: alarm  %v", alarmDefinition.AlarmId)
371                                         ricAlarmDefintion := new(alarm.AlarmDefinition)
372                                         ricAlarmDefintion.AlarmId = alarmDefinition.AlarmId
373                                         ricAlarmDefintion.AlarmText = alarmDefinition.AlarmText
374                                         ricAlarmDefintion.EventType = alarmDefinition.EventType
375                                         ricAlarmDefintion.OperationInstructions = alarmDefinition.OperationInstructions
376                                         ricAlarmDefintion.RaiseDelay = alarmDefinition.RaiseDelay
377                                         ricAlarmDefintion.ClearDelay = alarmDefinition.ClearDelay
378                                         alarm.RICAlarmDefinitions[alarmDefinition.AlarmId] = ricAlarmDefintion
379                                 }
380                         }
381                 } else {
382                         app.Logger.Error("ReadAlarmDefinitionFromJson: json.Unmarshal failed with error %v", err)
383                 }
384         } else {
385                 app.Logger.Error("ReadAlarmDefinitionFromJson: ioutil.ReadFile failed with error %v", err)
386         }
387 }
388
389 func (a *AlarmManager) ReadAlarmInfoFromPersistentVolume() {
390         var alarmpersistentinfo AlarmPersistentInfo
391         byteValue, rerr := ioutil.ReadFile(a.alarmInfoPvFile)
392         if rerr != nil {
393                 app.Logger.Error("ararminfo.json file read error %v", rerr)
394         } else {
395                 err := json.Unmarshal(byteValue, &alarmpersistentinfo)
396                 if err != nil {
397                         app.Logger.Error("alarmpersistentinfo json unmarshal error %v", err)
398                 } else {
399                         a.uniqueAlarmId = alarmpersistentinfo.UniqueAlarmId
400                         a.activeAlarms = make([]AlarmNotification, len(alarmpersistentinfo.ActiveAlarms))
401                         a.alarmHistory = make([]AlarmNotification, len(alarmpersistentinfo.AlarmHistory))
402                         copy(a.activeAlarms, alarmpersistentinfo.ActiveAlarms)
403                         copy(a.alarmHistory, alarmpersistentinfo.AlarmHistory)
404                 }
405         }
406 }
407
408 func (a *AlarmManager) WriteAlarmInfoToPersistentVolume() {
409         var alarmpersistentinfo AlarmPersistentInfo
410         alarmpersistentinfo.UniqueAlarmId = a.uniqueAlarmId
411         alarmpersistentinfo.ActiveAlarms = make([]AlarmNotification, len(a.activeAlarms))
412         alarmpersistentinfo.AlarmHistory = make([]AlarmNotification, len(a.alarmHistory))
413         copy(alarmpersistentinfo.ActiveAlarms, a.activeAlarms)
414         copy(alarmpersistentinfo.AlarmHistory, a.alarmHistory)
415         wdata, err := json.MarshalIndent(alarmpersistentinfo, "", " ")
416         if err != nil {
417                 app.Logger.Error("alarmpersistentinfo json marshal error %v", err)
418         } else {
419                 werr := ioutil.WriteFile(a.alarmInfoPvFile, wdata, 0777)
420                 if werr != nil {
421                         app.Logger.Error("alarminfo.json file write error %v", werr)
422                 }
423         }
424 }
425
426 func (a *AlarmManager) Run(sdlcheck bool) {
427         app.Logger.SetMdc("alarmManager", fmt.Sprintf("%s:%s", Version, Hash))
428         app.SetReadyCB(func(d interface{}) { a.rmrReady = true }, true)
429         app.Resource.InjectStatusCb(a.StatusCB)
430         app.AddConfigChangeListener(a.ConfigChangeCB)
431
432         alarm.RICAlarmDefinitions = make(map[int]*alarm.AlarmDefinition)
433         a.ReadAlarmDefinitionFromJson()
434
435         app.Resource.InjectRoute("/ric/v1/alarms", a.RaiseAlarm, "POST")
436         app.Resource.InjectRoute("/ric/v1/alarms", a.ClearAlarm, "DELETE")
437         app.Resource.InjectRoute("/ric/v1/alarms/active", a.GetActiveAlarms, "GET")
438         app.Resource.InjectRoute("/ric/v1/alarms/history", a.GetAlarmHistory, "GET")
439         app.Resource.InjectRoute("/ric/v1/alarms/config", a.SetAlarmConfig, "POST")
440         app.Resource.InjectRoute("/ric/v1/alarms/config", a.GetAlarmConfig, "GET")
441         app.Resource.InjectRoute("/ric/v1/alarms/define", a.SetAlarmDefinition, "POST")
442         app.Resource.InjectRoute("/ric/v1/alarms/define/{alarmId}", a.DeleteAlarmDefinition, "DELETE")
443         app.Resource.InjectRoute("/ric/v1/alarms/define", a.GetAlarmDefinition, "GET")
444         app.Resource.InjectRoute("/ric/v1/alarms/define/{alarmId}", a.GetAlarmDefinition, "GET")
445
446         // Start background timer for re-raising alerts
447         go a.StartAlertTimer()
448         a.alarmClient, _ = alarm.InitAlarm("SEP", "ALARMMANAGER")
449
450         a.ReadAlarmInfoFromPersistentVolume()
451
452         app.RunWithParams(a, sdlcheck)
453 }
454
455 func NewAlarmManager(amHost string, alertInterval int, clearAlarm bool) *AlarmManager {
456         if alertInterval == 0 {
457                 alertInterval = viper.GetInt("controls.promAlertManager.alertInterval")
458         }
459
460         if amHost == "" {
461                 amHost = viper.GetString("controls.promAlertManager.address")
462         }
463
464         return &AlarmManager{
465                 rmrReady:               false,
466                 postClear:              clearAlarm,
467                 amHost:                 amHost,
468                 amBaseUrl:              app.Config.GetString("controls.promAlertManager.baseUrl"),
469                 amSchemes:              []string{app.Config.GetString("controls.promAlertManager.schemes")},
470                 alertInterval:          alertInterval,
471                 activeAlarms:           make([]AlarmNotification, 0),
472                 alarmHistory:           make([]AlarmNotification, 0),
473                 uniqueAlarmId:          0,
474                 maxActiveAlarms:        app.Config.GetInt("controls.maxActiveAlarms"),
475                 maxAlarmHistory:        app.Config.GetInt("controls.maxAlarmHistory"),
476                 exceededActiveAlarmOn:  false,
477                 exceededAlarmHistoryOn: false,
478                 alarmInfoPvFile:        app.Config.GetString("controls.alarmInfoPvFile"),
479         }
480 }
481
482 // Main function
483 func main() {
484         NewAlarmManager("", 0, true).Run(true)
485 }