Add API allowing xAPPs to send alarm messages
[ric-plt/xapp-frame-cpp.git] / src / alarm / alarm.cpp
diff --git a/src/alarm/alarm.cpp b/src/alarm/alarm.cpp
new file mode 100644 (file)
index 0000000..2648ed1
--- /dev/null
@@ -0,0 +1,460 @@
+// vi: ts=4 sw=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       alarm.cpp
+       Abstract:       This class provides an API to the alarm collector/reporter.
+                               An object is insanced by the user xAPP allowing the xAPP
+                               to send, clear, or resend the alarm as is necessary.
+
+
+       Date:           15 July 2020
+       Author:         E. Scott Daniels
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <rmr/RIC_message_types.h>
+#ifndef RIC_ALARM
+       #define RIC_ALARM 110
+#endif
+
+#include <iostream>
+
+#include "msg_component.hpp"
+#include "message.hpp"
+#include "alarm.hpp"
+
+extern char* __progname;                       // runtime lib supplied since we don't get argv[0]
+
+namespace xapp {
+
+
+
+// ------ private ----------------------------------------------
+
+/*
+       Suss out the alarm target from environment.
+
+       We expect two variables in the environment:
+               ALARM_MGR_SERVICE_NAME
+               ALARM_MGR_SERVICE_PORT
+
+       If name is not given, localhost is assumed. If port is not given
+       then we assume 4560 (the defacto RMR listen port).
+*/
+static std::string endpoint_addr( ) {
+       char*   et;                                                                     // environment token
+       std::string addr = "localhost";
+       std::string port = "4560";
+
+       if( (et = getenv( "ALARM_MGR_SERVICE_NAME" )) != NULL ) {
+               addr = std::string( et );
+       }
+
+       if( (et = getenv( "ALARM_MGR_SERVICE_PORT" )) != NULL ) {
+               port = std::string( et );
+       }
+
+       return addr + ":" + port;
+}
+
+
+/*
+       Return the current time in milliseconds past the UNIX epoch.
+*/
+static long long now( void ) {
+       struct timespec ts;
+       long long       now = 0;
+
+       clock_gettime( CLOCK_REALTIME, &ts );
+       now = (ts.tv_sec * 1000000) + (ts.tv_nsec/1000000);     // convert nano to milli and bang onto seconds
+
+       return now;
+}
+
+
+/*
+       Build the alarm json message with the current data.
+       Returns the length of the payload inserted.
+*/
+int xapp::Alarm::build_alarm( int action_id, xapp::Msg_component payload, int payload_len ) {
+       //char  wbuf[4096];
+       std::string action;
+       int used;
+
+       if( app_id.compare( "" ) == 0 ) {
+               app_id = std::string( __progname );                             // see comment for extern above
+       }
+
+       if( severity.compare( "" ) == 0 ) {
+               Set_severity( Alarm::SEV_WARN );
+       }
+
+       switch( action_id ) {
+               case    Alarm::ACT_CLEAR:
+                       action = "CLEAR";
+                       break;
+
+               case    Alarm::ACT_CLEAR_ALL:
+                       action = "CLEARALL";
+                       break;
+
+               default:
+                       action = "RAISE";
+                       break;
+       }
+
+       //memset( wbuf, 0, sizeof( wbuf ) );
+       //snprintf( wbuf, sizeof( wbuf ),
+       used = snprintf( (char *) payload.get(), payload_len,
+                       "{  "
+                       "\"managedObjectId\": \"%s\", "
+                       "\"applicationId\": \"%s\", "
+                       "\"specificProblem\": %d, "
+                       "\"perceivedSeverity\": \"%s\", "
+                       "\"identifyingInfo\": \"%s\", "
+                       "\"additionalInfo\": \"%s\", "
+                       "\"AlarmAction\": \"%s\", "
+                       "\"AlarmTime\": %lld"
+                       " }",
+
+                       me_id.c_str(),
+                       app_id.c_str(),
+                       problem_id,
+                       severity.c_str(),
+                       info.c_str(),
+                       add_info.c_str(),
+                       action.c_str(),
+                       now()
+       );
+
+       //action = std::string( wbuf );
+       return used;
+}
+
+// --------------- builders/operators  -------------------------------------
+
+/*
+       Create a new message wrapper for an existing RMR msg buffer.
+
+       msg is a message which was allocaed by the framework and thus has the
+       mrc reference embedded.
+*/
+xapp::Alarm::Alarm( std::shared_ptr<Message> msg ) :
+       msg( msg ),
+       endpoint( endpoint_addr() ),
+       whid( -1 ),
+       app_id( "" ),
+       me_id( "" ),
+       problem_id( -1 ),
+       info( "" ),
+       add_info( "" ),
+       action( "" )
+{ /* empty body */ }
+
+/*
+       Parameterised constructor (avoids calling setters after creation).
+*/
+xapp::Alarm::Alarm( std::shared_ptr<Message> msg, int prob_id, std::string meid  ) :
+       msg( msg ),
+       endpoint( endpoint_addr() ),
+       whid( -1 ),
+       app_id( "" ),
+       me_id( meid ),
+       problem_id( prob_id ),
+       info( "" ),
+       add_info( "" ),
+       action( "" )
+{ /* empty body */ }
+
+xapp::Alarm::Alarm( std::shared_ptr<Message> msg, std::string meid  ) :
+       msg( msg ),
+       endpoint( endpoint_addr() ),
+       whid( -1 ),
+       app_id( "" ),
+       me_id( meid ),
+       problem_id( -1 ),
+       info( "" ),
+       add_info( "" ),
+       action( "" )
+{ /* empty body */ }
+
+
+
+// ------------------ copy and move support ---------------------------------
+
+/*
+       Copy builder.  Given a source object instance (soi), create a copy.
+       Creating a copy should be avoided as it can be SLOW!
+*/
+xapp::Alarm::Alarm( const Alarm& soi ) {
+       msg = soi.msg;
+       endpoint = soi.endpoint;
+       whid = soi.whid;
+
+       me_id = soi.me_id;                              // user stuff
+       app_id = soi.app_id;
+       problem_id = soi.problem_id;
+       severity = soi.severity;
+       info = soi.info;
+       add_info = soi.add_info;
+}
+
+/*
+       Assignment operator. Simiolar to the copycat, but "this" object exists and
+       may have data that needs to be released prior to making a copy of the soi.
+*/
+Alarm& xapp::Alarm::operator=( const Alarm& soi ) {
+       if( this != &soi ) {                            // cannot do self assignment
+               msg = soi.msg;
+               endpoint = soi.endpoint;
+               whid = soi.whid;
+
+               me_id = soi.me_id;
+               app_id = soi.app_id;
+               problem_id = soi.problem_id;
+               severity = soi.severity;
+               info = soi.info;
+               add_info = soi.add_info;
+       }
+
+       return *this;
+}
+
+/*
+       Move builder.  Given a source object instance (soi), move the information from
+       the soi ensuring that the destriction of the soi doesn't trash things from
+       under us.
+*/
+xapp::Alarm::Alarm( Alarm&& soi ) {
+       msg = soi.msg;          // capture pointers and copy data before setting soruce things to nil
+       endpoint = soi.endpoint;
+       whid = soi.whid;
+
+       me_id = soi.me_id;
+       app_id = soi.app_id;
+       problem_id = soi.problem_id;
+       severity = soi.severity;
+       info = soi.info;
+       add_info = soi.add_info;
+
+       soi.msg = NULL;         // prevent closing of RMR stuff on soi destroy
+}
+
+/*
+       Move Assignment operator. Move the message data to the existing object
+       ensure the object reference is cleaned up, and ensuring that the source
+       object references are removed.
+*/
+Alarm& xapp::Alarm::operator=( Alarm&& soi ) {
+       if( this != &soi ) {                            // cannot do self assignment
+               // anything that needs to be freed/delted from soi, must be done here
+
+               msg = soi.msg;                  // move pointers and values
+               endpoint = soi.endpoint;
+               whid = soi.whid;
+
+               me_id = soi.me_id;
+               app_id = soi.app_id;
+               problem_id = soi.problem_id;
+               severity = soi.severity;
+               info = soi.info;
+               add_info = soi.add_info;
+
+               soi.msg = NULL;                 // prevent bad things when source is destroyed
+       }
+
+       return *this;
+}
+
+/*
+       Destroyer.
+*/
+xapp::Alarm::~Alarm() {
+
+       msg = NULL;
+}
+
+
+// ---- setters -------------------------------------------------
+
+void xapp::Alarm::Set_meid( std::string new_meid ) {
+       me_id = new_meid;
+}
+
+void xapp::Alarm::Set_severity( int new_sev ) {
+       switch( new_sev ) {
+               case    Alarm::SEV_CRIT:
+                       severity = "CRITICAL";
+                       break;
+
+               case    Alarm::SEV_MAJOR:
+                       severity = "MAJOR";
+                       break;
+
+               case    Alarm::SEV_MINOR:
+                       severity = "MINOR";
+                       break;
+
+               case    Alarm::SEV_WARN:
+                       severity = "WARNING";
+                       break;
+
+               case    Alarm::SEV_CLEAR:
+                       severity = "CLEARED";
+                       break;
+
+               default:
+                       severity = "DEFAULT";
+                       break;
+       }
+}
+
+void xapp::Alarm::Set_appid( std::string new_id ) {
+       app_id = new_id;
+}
+
+void xapp::Alarm::Set_problem( int new_id ) {
+       problem_id = new_id;
+}
+
+void xapp::Alarm::Set_info( std::string new_info ) {
+       info = new_info;
+}
+
+void xapp::Alarm::Set_additional( std::string new_info ) {
+       add_info = new_info;
+}
+
+void xapp::Alarm::Set_whid( int new_whid ) {
+       whid = new_whid;
+}
+
+void xapp::Alarm::Dump() {
+       fprintf( stderr, "Alarm: prob id: %d\n", problem_id );
+       fprintf( stderr, "Alarm: meid: %s\n", me_id.c_str() );
+       fprintf( stderr, "Alarm: app: %s\n", app_id.c_str() );
+       fprintf( stderr, "Alarm: info: %s\n", info.c_str() );
+       fprintf( stderr, "Alarm: ainfo: %s\n", add_info.c_str() );
+}
+
+// ------------------- getters ------------------------------------
+
+/*
+       Return the enpoint address string we have.
+*/
+std::string xapp::Alarm::Get_endpoint( ) {
+       return endpoint;
+}
+
+// ------- message sending ---------------------------------------
+
+/*
+       Send a raise message with the alarm contents unchanged.
+*/
+bool xapp::Alarm::Raise( ) {
+       int used;
+       used = build_alarm( ACT_RAISE, msg->Get_payload(), msg->Get_available_size() );
+       msg->Wormhole_send( whid,  RIC_ALARM, xapp::Message::NO_SUBID, used + 1, NULL );
+}
+
+/*
+       Additional prototypes allow for avoiding some setter calls when raising alarms.
+       Severity is one of our SEV_* constants. Problem is the caller's assigned
+       problem ID. Info and addional_info are user supplied data that is just passed
+       through.
+*/
+bool xapp::Alarm::Raise( int severity, int problem, std::string info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+
+       Raise();
+}
+
+bool xapp::Alarm::Raise( int severity, int problem, std::string info, std::string additional_info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+       this->add_info = additional_info;
+
+       Raise();
+}
+
+/*
+       Send a clear message with the contents of the alarm otherwise unchanged.
+*/
+bool xapp::Alarm::Clear( ) {
+       int used;
+
+       used = build_alarm( ACT_CLEAR, msg->Get_payload(), msg->Get_available_size() );
+       msg->Wormhole_send( whid,  RIC_ALARM, xapp::Message::NO_SUBID, used + 1, NULL );
+}
+
+/*
+       Additional prototypes allow for avoiding some setter calls when raising alarms.
+       Severity is one of our SEV_* constants. Problem is the caller's assigned
+       problem ID. Info and addional_info are user supplied data that is just passed
+       through.
+*/
+bool xapp::Alarm::Clear( int severity, int problem, std::string info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+
+       Clear();
+}
+
+bool xapp::Alarm::Clear( int severity, int problem, std::string info, std::string additional_info ) {
+       this->severity = severity;
+       problem_id = problem;
+       this->info = info;
+       this->add_info = additional_info;
+
+       Clear();
+}
+
+
+/*
+       Send a clear-all message. The contents of the alarm are unaffected.
+*/
+bool xapp::Alarm::Clear_all( ) {
+       int used;
+
+       used = build_alarm( ACT_CLEAR_ALL, msg->Get_payload(), msg->Get_available_size() );
+       msg->Wormhole_send( whid,  RIC_ALARM, xapp::Message::NO_SUBID, used + 1, NULL );
+}
+
+
+/*
+       This is a convenience function which sends a clear message followed by a
+       raise message. Alarm contents are not adjusted.
+*/
+bool xapp::Alarm::Raise_again( ) {
+       Clear();
+       Raise();
+}
+
+
+
+} // namespace