Add health check to the MC-listener application 39/2739/2
authorE. Scott Daniels <daniels@research.att.com>
Tue, 10 Mar 2020 19:35:03 +0000 (15:35 -0400)
committerE. Scott Daniels <daniels@research.att.com>
Tue, 10 Mar 2020 19:48:54 +0000 (15:48 -0400)
This change adds the ability of the mc-listener applicaiton to
respond to an RMR health check message.

Issue-ID: RICAPP-25

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: Icabedd3d54783fbfbe2a32c5329a0f43413d80bb

sidecars/listener/Dockerfile
sidecars/listener/build_images.sh
sidecars/listener/mcl.c
sidecars/listener/run_unit_test.ksh
sidecars/listener/test_rmr_em.c
sidecars/listener/unit_test.c

index b07aed5..861401f 100644 (file)
@@ -48,7 +48,7 @@ RUN apt-get update && apt-get install -y cmake gcc make git g++ wget
 
 WORKDIR /playpen
 # Install RMr (runtime and dev) from debian package cached on packagecloud.io
-ARG RMR_VER=3.1.2
+ARG RMR_VER=3.5.1
 
 RUN wget -nv --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_${RMR_VER}_amd64.deb/download.deb
 RUN wget -nv --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_${RMR_VER}_amd64.deb/download.deb
index d32b4f5..30b9a9b 100755 (executable)
@@ -20,7 +20,8 @@
 #------------------------------------------------------------------------------------
 #      Mnemonic:       build_images.sh
 #      Abstract:       This script will create both the mc_listener runtime and development
-#                              images.
+#                              images when "all" is given on the command line, otherwise it builds
+#                              just a runtime environment.
 #      Date:           22 August 2-19
 #      Author:         E. Scott Daniels
 # -----------------------------------------------------------------------------------
@@ -40,8 +41,8 @@ then
 fi
 
 
-ver=${1:-1.2}
-patch=${2:-1}
+ver=${1:-1.3}
+patch=${2:-0}
 
 if (( skip_dev == 0 ))
 then
@@ -49,8 +50,9 @@ then
        docker build -f mcl_dev.df -t mcl_dev:$ver.$patch .
 fi
 
+# use the main dockerfile for the runtime image
 echo "building runtime image mc_listener:$ver"
-if docker build -f mcl_runtime.df -t mc_listener:$ver.$patch .
+if docker build -f Dockerfile -t mc_listener:$ver.$patch .
 then
        echo "build finished"
        echo ""
index 764be7e..00aee96 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <rmr/rmr.h>
 #include <rmr/rmr_symtab.h>
+#include <rmr/RIC_message_types.h>
 
 #include "mcl.h"
 
@@ -148,18 +149,27 @@ static void* setup_rdc() {
        dest is nil. The header is of the form:
                <delim><len><timestamp>
 
+       Field lengths (bytes) are:
+               delim           4      
+               len                     8       (7 digits + 0)
+               timestamp       16  (15 digits + 0)
+
+       
        Timestamp is a single unsigned long long in ASCII; ms since epoch.
        If the current time is 2019/10/03 10:39:51.103 which is 1570113591.103
-       the timestamp generated will be 1570113591103.
+       the timestamp generated will be 1570113591103. 
+
+       The lenght and timestamp fields in the header are zero terminated so 
+       they can be parsed as a string (atoi etc).
 */
 static char* build_hdr( int len, char* dest, int dest_len ) {
        struct timespec ts;         // time just before call executed
 
        if( dest == NULL ) {
-               dest_len = 48;
+               dest_len = MCL_EXHDR_SIZE + 2;                  // more than enough room
                dest = (char *) malloc( sizeof( char ) * dest_len );
        } else {
-               if( dest_len < 28 ) {           // shouldn't happen, but take no chances
+               if( dest_len < MCL_EXHDR_SIZE ) {               // shouldn't happen, but take no chances
                        memset( dest, 0, dest_len );
                        return NULL;
                }
@@ -168,8 +178,8 @@ static char* build_hdr( int len, char* dest, int dest_len ) {
        memset( dest, 0, dest_len );
 
        clock_gettime( CLOCK_REALTIME, &ts );
-       sprintf( dest, "%s%07d", MCL_DELIM, len );
-       sprintf( dest+12, "%ld%03ld", ts.tv_sec, ts.tv_nsec/1000000 );
+       snprintf( dest, dest_len, "%s%07d", MCL_DELIM, len );
+       snprintf( dest+12, dest_len-13, "%ld%03ld", ts.tv_sec, ts.tv_nsec/1000000 );
 
        return dest;
 }
@@ -493,7 +503,7 @@ static int fifo_read1( void *vctx, int mtype, char* ubuf, int ublen, int long_hd
                        read_header( fd, wbuf );
                        msg_len = need = atoi( wbuf + MCL_LEN_OFF );                            // read the length
                        if( timestamp ) {
-                               strcpy( timestamp, wbuf + MCL_TSTAMP_OFF+1 );
+                               strncpy( timestamp, wbuf + MCL_TSTAMP_OFF+1, MCL_TSTAMP_SIZE );
                        }
                } else {
                        if( timestamp != NULL ) {                                               // won't be there, but ensure it's not garbage
@@ -566,8 +576,12 @@ extern int mcl_fifo_tsread1( void *vctx, int mtype, char* ubuf, int ublen, int l
 
        If long_hdr is true, then we geneate an extended header with a delimiter and
        timestamp.
+
+       The one message which is NOT pushed into a FIFO is the RIC_HEALTH_CHECK_REQ
+       message.  When the health check message is received it is responded to 
+       with the current state of processing (ok or err).
 */
-extern void mcl_fifo_fanout( void* vctx, int report, int long_hdr  ) {
+extern void mcl_fifo_fanout( void* vctx, int report, int long_hdr ) {
        mcl_ctx_t*      ctx;                                    // our context; mostly for the rmr context reference and symtable
        fifo_t*         fifo;                                   // fifo to chalk counts on
        rmr_mbuf_t*     mbuf = NULL;                    // received message buffer; recycled on each call
@@ -600,36 +614,47 @@ extern void mcl_fifo_fanout( void* vctx, int report, int long_hdr  ) {
        do {
                mbuf = mcl_get_msg( ctx, mbuf, report );                        // wait up to report sec for msg (0 == block until message)
 
-               if( mbuf != NULL && mbuf->state == RMR_OK && mbuf->len > 0  ) {
-                       fd = suss_fifo( ctx, mbuf->mtype, WRITER, &fifo );              // map the message type to an open fd
-                       if( fd >= 0 ) {
-                               if( long_hdr ) {
-                                       build_hdr( mbuf->len, header, sizeof( header ) );
-                                       hwlen = MCL_EXHDR_SIZE;
-                               } else {
-                                       snprintf( header, sizeof( header ), "%07d", mbuf->len );                        // size of payload CAUTION: 7d is MCL_LEN_SIZE-1
-                                       hwlen = MCL_LEN_SIZE;
-                               }
+               if( mbuf != NULL && mbuf->state == RMR_OK ) {
+                       if( mbuf->mtype == RIC_HEALTH_CHECK_REQ ) {
+                               mbuf->mtype = RIC_HEALTH_CHECK_RESP;            // if we're here we are running and all is ok
+                               mbuf->sub_id = -1;
+                               mbuf = rmr_realloc_payload( mbuf, 128, FALSE, FALSE );  // ensure payload is large enough
+                               strncpy( mbuf->payload, "OK\n", rmr_payload_size( mbuf) );
+                               rmr_rts_msg( ctx->mrc, mbuf );
+                               continue;
+                       }
+                       
+                       if( mbuf->len > 0  ) {
+                               fd = suss_fifo( ctx, mbuf->mtype, WRITER, &fifo );              // map the message type to an open fd
+                               if( fd >= 0 ) {
+                                       if( long_hdr ) {
+                                               build_hdr( mbuf->len, header, sizeof( header ) );
+                                               hwlen = MCL_EXHDR_SIZE;
+                                       } else {
+                                               snprintf( header, sizeof( header ), "%07d", mbuf->len );                        // size of payload CAUTION: 7d is MCL_LEN_SIZE-1
+                                               hwlen = MCL_LEN_SIZE;
+                                       }
 
-                               if( (state = write( fd, header, hwlen )) != hwlen ) {           // write exactly MCL_LEN_SIZE bytes from the buffer
-                                       drops++;
-                                       total_drops++;
-                                       chalk_error( fifo );
-                               } else {
-                                       if( write( fd, mbuf->payload, mbuf->len ) < mbuf->len ) {                       // followed by the payload
-                                               errors++;
+                                       if( (state = write( fd, header, hwlen )) != hwlen ) {           // write exactly MCL_LEN_SIZE bytes from the buffer
+                                               drops++;
+                                               total_drops++;
                                                chalk_error( fifo );
                                        } else {
-                                               chalk_ok( fifo );
-                                               count++;
-                                               total++;
+                                               if( write( fd, mbuf->payload, mbuf->len ) < mbuf->len ) {                       // followed by the payload
+                                                       errors++;
+                                                       chalk_error( fifo );
+                                               } else {
+                                                       chalk_ok( fifo );
+                                                       count++;
+                                                       total++;
+                                               }
                                        }
                                }
-                       }
 
-                       if( rdc_ctx != NULL ) {
-                               rdc_buf = rdc_init_buf( mbuf->mtype, header, hwlen, rdc_buf );                  // set up for write
-                               rdc_write( rdc_ctx, rdc_buf, mbuf->payload, mbuf->len );                                                // write the raw data
+                               if( rdc_ctx != NULL ) {
+                                       rdc_buf = rdc_init_buf( mbuf->mtype, header, hwlen, rdc_buf );                  // set up for write
+                                       rdc_write( rdc_ctx, rdc_buf, mbuf->payload, mbuf->len );                                                // write the raw data
+                               }
                        }
                }
 
index e20f738..757b81e 100755 (executable)
 #      Author:         E. Scott Daniels
 # -------------------------------------------------------------------------
 
+function abort_after {
+       touch /tmp/running
+       sleep ${1:-60}
+       if [[ -e /tmp/running ]]
+       then
+               echo "abort: unit test running too long"
+               kill -9 ${2:-bad-pid}
+       fi
+}
+
 function setup_dirs {
        mkdir -p /tmp/fifos
        mkdir -p /tmp/mc_listener_test/final
@@ -67,13 +77,16 @@ then
        exit
 fi
 
+abort_after 60 
 if ! unit_test >/tmp/PID$$.utlog 2>&1
 then
+       rm /tmp/running
        cat /tmp/PID$$.utlog
        rm -f /tmp/PID$$.*
        purge_dirs
        exit 1
 fi
+rm /tmp/running
 
 echo "[PASS] base unit tests all pass"
 echo "[INFO] file/directory verification begins...."
index 5034b77..5976a2c 100644 (file)
 */
 
 #include <rmr/rmr.h>
+#include <rmr/RIC_message_types.h>
 
-#define rmr_torcv_msg RMR_torcv_msg
 
+/*
+       The first call will generate a timeout for testing. All others will
+       succeed with a message.
+*/
 extern rmr_mbuf_t* RMR_torcv_msg( void* ctx, rmr_mbuf_t* old_msg, int ms_to ) {
        static int timeout = 0;
+       static int hcheck = 0;
 
        if( old_msg == NULL ) {
                old_msg = rmr_alloc_msg( ctx, 256 );
@@ -49,12 +54,52 @@ extern rmr_mbuf_t* RMR_torcv_msg( void* ctx, rmr_mbuf_t* old_msg, int ms_to ) {
                return old_msg; 
        }
 
+       if( !hcheck ) {                                                                 // send one health check message
+               old_msg->mtype = RIC_HEALTH_CHECK_REQ;
+               old_msg->state = 0;
+               hcheck = 1;
+               return old_msg;
+       }
+
 
-       snprintf( old_msg->payload, 100, "DUMMY MESSAGE" );
-       old_msg->mtype = 100;
+       snprintf( old_msg->payload, rmr_payload_size( old_msg ), "DUMMY MESSAGE" );
+       old_msg->mtype = TEST_MTYPE;
        old_msg->len = strlen( old_msg->payload );
        old_msg->sub_id = -1;
        old_msg->state = 0;
 
        return old_msg;
 }
+
+/*
+       Always successful if a message was passed in.
+*/
+extern rmr_mbuf_t* RMR_rts_msg( void* ctx, rmr_mbuf_t* msg ) {
+       if( msg != NULL ) {
+               msg->state = 0;
+       }
+
+       return msg;
+}
+
+/*
+       Generates "short" reads 9 out of 10 times so that we can
+       drive the buffer construction code that otherwise wouldn't
+       be driven since long reads are usually the case.
+*/
+extern int Read( int fd, char* dest, int max ) {
+       static int count = -1;
+
+       count++;
+
+       if( count % 10 ) {
+               return read( fd, dest, max );           // return long read
+       }
+
+       return read( fd, dest, 3 );             // short read
+}
+
+// ----------- defines that point included code here --------------------
+#define rmr_torcv_msg RMR_torcv_msg
+#define rmr_rts_msg RMR_rts_msg
+#define read Read
index 9699f6c..edcc139 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#define TEST_MTYPE     1000            // message type for testing
 #include "test_rmr_em.c"               // emulated rmr functions (for receives)
 
 // this/these are what we are testing; include them directly (must be after forever def)
@@ -89,14 +90,14 @@ int main( int argc,  char** argv ) {
 
        mcl_set_sigh();                                                                         // prevent colobber from broken pipe
 
-       open_fifo( ctx, 100, WRITER );                                          // open dummy to prevent blocking reader
-       rfd = open_fifo( ctx, 100, READER );                            // open a reader to check fanout output
+       open_fifo( ctx, TEST_MTYPE, WRITER );                                           // open dummy to prevent blocking reader
+       rfd = open_fifo( ctx, TEST_MTYPE, READER );                             // open a reader to check fanout output
        if( rfd < 0 ) {
                fprintf( stderr, "[FAIL] unable to open a pipe reader for type == 100\n" );
                errors++;
        }
 
-       fd = suss_fifo( ctx, 100, 1, &fref );                           // should open the file for writing and return the fdes
+       fd = suss_fifo( ctx, TEST_MTYPE, WRITER, &fref );                       // should open the file for writing and return the fdes
        if( fd < 0 ) {
                fprintf( stderr, "[FAIL] suss_fifo did not return a valid fd\n" );
                errors++;
@@ -110,7 +111,7 @@ int main( int argc,  char** argv ) {
                chalk_error( fref );
        }
 
-       fd2= suss_fifo( ctx, 100, 0, NULL );                            // should open the file file for reading and return a different fd
+       fd2= suss_fifo( ctx, TEST_MTYPE, 0, NULL );                             // should open the file file for reading and return a different fd
        if( fd < 0 ) {
                fprintf( stderr, "[FAIL] suss_fifo did not return a valid fd\n" );
                errors++;
@@ -122,25 +123,28 @@ int main( int argc,  char** argv ) {
 
        mcl_start_listening( ctx, port, 0 );                    // start the listener
 
-                                                                                                       // under test, the forever keeps fanout from blocking; drive for each of two cases:
+       // under test, the FOREVER = 0 keeps fanout from blocking; drive several times to cover all cases
        mcl_fifo_fanout( ctx, 5, 1 );                                   // first rmr receive call will simulate a timeout
-       mcl_fifo_fanout( ctx, 5, 1 );                                   // second receive call simualtes a message arriving
-       mcl_fifo_fanout( ctx, 5, 1 );                                   // another round so there are two to read
+       mcl_fifo_fanout( ctx, 5, 1 );                                   // second receive simulates a health check
+       mcl_fifo_fanout( ctx, 5, 1 );                                   // 3-n return alternating timeout messages; drive so that 
+       mcl_fifo_fanout( ctx, 5, 1 );                                   // we will have several land in the FIFO
+       mcl_fifo_fanout( ctx, 5, 1 );
+       mcl_fifo_fanout( ctx, 5, 1 );
        mcl_fifo_fanout( ctx, 5, 1 );
 
        *timestamp = 0;
-       state = mcl_fifo_read1( ctx, 100, payload, sizeof( payload ), TRUE );
+       state = mcl_fifo_read1( ctx, TEST_MTYPE, payload, sizeof( payload ), TRUE );
        if( state < 1 ) {
                fprintf( stderr, "[FAIL] fifo_read return positive value when expected to\n" );
                errors++;
        }
-       state = mcl_fifo_tsread1( ctx, 100, payload, sizeof( payload ), TRUE, timestamp );
+       state = mcl_fifo_tsread1( ctx, TEST_MTYPE, payload, sizeof( payload ), TRUE, timestamp );
        if( state < 1 ) {
                fprintf( stderr, "[FAIL] fifo_read with timestamp return positive value when expected to\n" );
                errors++;
        }
 
-       state = fifo_read1( NULL, 100, payload, sizeof( payload ), 1, timestamp );              // coverage error check
+       state = fifo_read1( NULL, TEST_MTYPE, payload, sizeof( payload ), 1, timestamp );               // coverage error check
        if( state != 0 ) {
                fprintf( stderr, "[FAIL] fifo_read didn't return 0 when given a nil context to\n" );
                errors++;
@@ -162,7 +166,7 @@ int main( int argc,  char** argv ) {
        }
 
        fref = NULL;
-       fd = suss_fifo( bad_ctx, 100, 1, &fref );                               // should fail to open the file for writing beacuse directory is bad
+       fd = suss_fifo( bad_ctx, TEST_MTYPE, 1, &fref );                                // should fail to open the file for writing beacuse directory is bad
        if( fd >= 0 ) {
                fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a context with a bad directory path\n" );
                errors++;
@@ -172,7 +176,7 @@ int main( int argc,  char** argv ) {
                errors++;
        }
 
-       fd = suss_fifo( NULL, 100, 1, &fref );                          // coverage nil pointer check
+       fd = suss_fifo( NULL, TEST_MTYPE, 1, &fref );                           // coverage nil pointer check
        if( fd >= 0 ) {
                fprintf( stderr, "[FAIL] suss_fifo returned a valid fd when given a nil context a bad directory path\n" );
                errors++;
@@ -231,14 +235,14 @@ int main( int argc,  char** argv ) {
 
        build_hdr( 1024, wbuf, sizeof( wbuf ) );
        bp = NULL;
-       bp = rdc_init_buf( 100, wbuf, 10, bp );                                 // set up for write
+       bp = rdc_init_buf( TEST_MTYPE, wbuf, 10, bp );                                  // set up for write
        rdc_write( ctx, bp, payload, sizeof( payload ) );                               // write the raw data
 
        fprintf( stderr, "[INFO] pausing to test rdc file rolling\n" );
        sleep( 15 );
        build_hdr( 1024, wbuf, sizeof( wbuf ) );
        bp = NULL;
-       bp = rdc_init_buf( 100, wbuf, 10, bp );
+       bp = rdc_init_buf( TEST_MTYPE, wbuf, 10, bp );
        rdc_write( ctx, bp, payload, sizeof( payload ) );