3380caceefb276085f7a133501bb6c44e446fe48
[demo.git] / vnfs / VES / code / evel_library / evel.c
1 /**************************************************************************//**
2  * @file
3  * Source module isolating the ECOMP Vendor Event Listener (EVEL) API.
4  *
5  * This file implements the EVEL library which is intended to provide a
6  * simple wrapper around the complexity of AT&T's Vendor Event Listener API so
7  * that VNFs can use it without worrying about details of:
8  *
9  *  *   The API's encoding into JSON.
10  *  *   The API's transport over HTTP/HTTPS.
11  *
12  * License
13  * -------
14  *
15  * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are met:
19  *
20  * 1. Redistributions of source code must retain the above copyright notice,
21  *    this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright notice,
23  *    this list of conditions and the following disclaimer in the documentation
24  *    and/or other materials provided with the distribution.
25  * 3. All advertising materials mentioning features or use of this software
26  *    must display the following acknowledgement:  This product includes
27  *    software developed by the AT&T.
28  * 4. Neither the name of AT&T nor the names of its contributors may be used to
29  *    endorse or promote products derived from this software without specific
30  *    prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
33  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
36  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
41  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *****************************************************************************/
43
44 #include <string.h>
45 #include <assert.h>
46 #include <stdlib.h>
47 #include <sys/time.h>
48 #include <curl/curl.h>
49
50 #include "evel.h"
51 #include "evel_internal.h"
52 #include "evel_throttle.h"
53 #include "metadata.h"
54
55 /**************************************************************************//**
56  * The type of equipment represented by this VNF.
57  *****************************************************************************/
58 EVEL_SOURCE_TYPES event_source_type = EVEL_SOURCE_OTHER;
59
60 /**************************************************************************//**
61  * The Functional Role of the equipment represented by this VNF.
62  *****************************************************************************/
63 char *functional_role = NULL;
64
65 /**************************************************************************//**
66  * Library initialization.
67  *
68  * Initialize the EVEL library.
69  *
70  * @note  This function initializes the cURL library.  Applications making use
71  *        of libcurl may need to pull the initialization out of here.  Note
72  *        also that this function is not threadsafe as a result - refer to
73  *        libcurl's API documentation for relevant warnings.
74  *
75  * @sa  Matching Term function.
76  *
77  * @param   fqdn    The API's FQDN or IP address.
78  * @param   port    The API's port.
79  * @param   path    The optional path (may be NULL).
80  * @param   topic   The optional topic part of the URL (may be NULL).
81  * @param   secure  Whether to use HTTPS (0=HTTP, 1=HTTPS)
82  * @param   username  Username for Basic Authentication of requests.
83  * @param   password  Password for Basic Authentication of requests.
84  * @param   source_type The kind of node we represent.
85  * @param   role    The role this node undertakes.
86  * @param   verbosity  0 for normal operation, positive values for chattier
87  *                        logs.
88  *
89  * @returns Status code
90  * @retval  EVEL_SUCCESS      On success
91  * @retval  ::EVEL_ERR_CODES  On failure.
92  *****************************************************************************/
93 EVEL_ERR_CODES evel_initialize(const char * const fqdn,
94                                int port,
95                                const char * const path,
96                                const char * const topic,
97                                int secure,
98                                const char * const username,
99                                const char * const password,
100                                EVEL_SOURCE_TYPES source_type,
101                                const char * const role,
102                                int verbosity
103                                )
104 {
105   EVEL_ERR_CODES rc = EVEL_SUCCESS;
106   char base_api_url[EVEL_MAX_URL_LEN + 1] = {0};
107   char event_api_url[EVEL_MAX_URL_LEN + 1] = {0};
108   char throt_api_url[EVEL_MAX_URL_LEN + 1] = {0};
109   char path_url[EVEL_MAX_URL_LEN + 1] = {0};
110   char topic_url[EVEL_MAX_URL_LEN + 1] = {0};
111   char version_string[10] = {0};
112   int offset;
113
114   /***************************************************************************/
115   /* Check assumptions.                                                      */
116   /***************************************************************************/
117   assert(fqdn != NULL);
118   assert(port > 0 && port <= 65535);
119   assert(source_type < EVEL_MAX_SOURCE_TYPES);
120   assert(role != NULL);
121
122   /***************************************************************************/
123   /* Start logging so we can report on progress.                             */
124   /***************************************************************************/
125   log_initialize(verbosity == 0 ? EVEL_LOG_INFO : EVEL_LOG_DEBUG, "EVEL");
126   EVEL_INFO("EVEL started");
127   EVEL_INFO("API server is: %s", fqdn);
128   EVEL_INFO("API port is: %d", port);
129
130   if (path != NULL)
131   {
132     EVEL_INFO("API path is: %s", path);
133   }
134   else
135   {
136     EVEL_INFO("No API path");
137   }
138
139   if (topic != NULL)
140   {
141     EVEL_INFO("API topic is: %s", topic);
142   }
143   else
144   {
145     EVEL_INFO("No API topic");
146   }
147
148   EVEL_INFO("API transport is: %s", secure ? "HTTPS" : "HTTP");
149   EVEL_INFO("Event Source Type is: %d", source_type);
150   EVEL_INFO("Functional Role is: %s", role);
151   EVEL_INFO("Log verbosity is: %d", verbosity);
152
153   /***************************************************************************/
154   /* Initialize event throttling to the default state.                       */
155   /***************************************************************************/
156   evel_throttle_initialize();
157
158   /***************************************************************************/
159   /* Save values we will need during operation.                              */
160   /***************************************************************************/
161   event_source_type = source_type;
162   functional_role = strdup(role);
163
164   /***************************************************************************/
165   /* Ensure there are no trailing zeroes and unnecessary decimal points in   */
166   /* the version.                                                            */
167   /***************************************************************************/
168   offset = sprintf(version_string, "%d", EVEL_API_MAJOR_VERSION);
169
170   if (EVEL_API_MINOR_VERSION != 0)
171   {
172     sprintf(version_string + offset, ".%d", EVEL_API_MINOR_VERSION);
173   }
174
175   /***************************************************************************/
176   /* Build a common base of the API URLs.                                    */
177   /***************************************************************************/
178   strcpy(path_url, "/");
179   snprintf(base_api_url,
180            EVEL_MAX_URL_LEN,
181            "%s://%s:%d%s/eventListener/v%s",
182            secure ? "https" : "http",
183            fqdn,
184            port,
185            (((path != NULL) && (strlen(path) > 0)) ?
186             strncat(path_url, path, EVEL_MAX_URL_LEN) : ""),
187            version_string);
188
189   /***************************************************************************/
190   /* Build the URL to the event API.                                         */
191   /***************************************************************************/
192   strcpy(topic_url, "/");
193   snprintf(event_api_url,
194            EVEL_MAX_URL_LEN,
195            "%s%s",
196            base_api_url,
197            (((topic != NULL) && (strlen(topic) > 0)) ?
198             strncat(topic_url, topic, EVEL_MAX_URL_LEN) : ""));
199   EVEL_INFO("Vendor Event Listener API is located at: %s", event_api_url);
200
201   /***************************************************************************/
202   /* Build the URL to the throttling API.                                    */
203   /***************************************************************************/
204   snprintf(throt_api_url,
205            EVEL_MAX_URL_LEN,
206            "%s/clientThrottlingState",
207            base_api_url);
208   EVEL_INFO("Vendor Event Throttling API is located at: %s", throt_api_url);
209
210   /***************************************************************************/
211   /* Spin-up the event-handler, which gets cURL readied for use.             */
212   /***************************************************************************/
213   rc = event_handler_initialize(event_api_url,
214                                 throt_api_url,
215                                 username,
216                                 password,
217                                 verbosity);
218   if (rc != EVEL_SUCCESS)
219   {
220     log_error_state("Failed to initialize event handler (including cURL)");
221     goto exit_label;
222   }
223
224   /***************************************************************************/
225   /* Extract the metadata from OpenStack. If we fail to extract it, we       */
226   /* record that in the logs, but carry on, assuming we're in a test         */
227   /* without a metadata service.                                             */
228   /***************************************************************************/
229   rc = openstack_metadata(verbosity);
230   if (rc != EVEL_SUCCESS)
231   {
232     EVEL_INFO("Failed to load OpenStack metadata - assuming test environment");
233     rc = EVEL_SUCCESS;
234   }
235
236   /***************************************************************************/
237   /* Start the event handler thread.                                         */
238   /***************************************************************************/
239   rc = event_handler_run();
240   if (rc != EVEL_SUCCESS)
241   {
242     log_error_state("Failed to start event handler thread. "
243                     "Error code=%d", rc);
244     goto exit_label;
245   }
246
247 exit_label:
248   return(rc);
249 }
250
251 /**************************************************************************//**
252  * Clean up the EVEL library.
253  *
254  * @note that at present don't expect Init/Term cycling not to leak memory!
255  *
256  * @returns Status code
257  * @retval  EVEL_SUCCESS On success
258  * @retval  "One of ::EVEL_ERR_CODES" On failure.
259  *****************************************************************************/
260 EVEL_ERR_CODES evel_terminate(void)
261 {
262   int rc = EVEL_SUCCESS;
263
264   /***************************************************************************/
265   /* First terminate any pending transactions in the event-posting thread.   */
266   /***************************************************************************/
267   rc = event_handler_terminate();
268   if (rc != EVEL_SUCCESS)
269   {
270     log_error_state("Failed to terminate EVEL library cleanly!");
271   }
272
273   /***************************************************************************/
274   /* Shut down the Event Handler library in a tidy manner.                   */
275   /***************************************************************************/
276   curl_global_cleanup();
277
278   /***************************************************************************/
279   /* Clean up allocated memory.                                              */
280   /***************************************************************************/
281   free(functional_role);
282
283   /***************************************************************************/
284   /* Clean up event throttling.                                              */
285   /***************************************************************************/
286   evel_throttle_terminate();
287
288   EVEL_INFO("EVEL stopped");
289   return(rc);
290 }
291
292 /**************************************************************************//**
293  * Free an event.
294  *
295  * Free off the event supplied.  Will free all the contained allocated memory.
296  *
297  * @note  It is safe to free a NULL pointer.
298  *****************************************************************************/
299 void evel_free_event(void * event)
300 {
301   EVENT_HEADER * evt_ptr = event;
302   EVEL_ENTER();
303
304   if (event != NULL)
305   {
306     /*************************************************************************/
307     /* Work out what kind of event we're dealing with so we can cast it      */
308     /* appropriately.                                                        */
309     /*************************************************************************/
310     switch (evt_ptr->event_domain)
311     {
312     case EVEL_DOMAIN_INTERNAL:
313       EVEL_DEBUG("Event is an Internal event at %lp", evt_ptr);
314       evel_free_internal_event((EVENT_INTERNAL *) evt_ptr);
315       memset(evt_ptr, 0, sizeof(EVENT_INTERNAL));
316       free(evt_ptr);
317       break;
318
319     case EVEL_DOMAIN_HEARTBEAT:
320       EVEL_DEBUG("Event is a Heartbeat at %lp", evt_ptr);
321       evel_free_header(evt_ptr);
322       memset(evt_ptr, 0, sizeof(EVENT_HEADER));
323       free(evt_ptr);
324       break;
325
326     case EVEL_DOMAIN_FAULT:
327       EVEL_DEBUG("Event is a Fault at %lp", evt_ptr);
328       evel_free_fault((EVENT_FAULT *)evt_ptr);
329       memset(evt_ptr, 0, sizeof(EVENT_FAULT));
330       free(evt_ptr);
331       break;
332
333     case EVEL_DOMAIN_MEASUREMENT:
334       EVEL_DEBUG("Event is a Measurement at %lp", evt_ptr);
335       evel_free_measurement((EVENT_MEASUREMENT *)evt_ptr);
336       memset(evt_ptr, 0, sizeof(EVENT_MEASUREMENT));
337       free(evt_ptr);
338       break;
339
340     case EVEL_DOMAIN_MOBILE_FLOW:
341       EVEL_DEBUG("Event is a Mobile Flow at %lp", evt_ptr);
342       evel_free_mobile_flow((EVENT_MOBILE_FLOW *)evt_ptr);
343       memset(evt_ptr, 0, sizeof(EVENT_MOBILE_FLOW));
344       free(evt_ptr);
345       break;
346
347     case EVEL_DOMAIN_REPORT:
348       EVEL_DEBUG("Event is a Report at %lp", evt_ptr);
349       evel_free_report((EVENT_REPORT *)evt_ptr);
350       memset(evt_ptr, 0, sizeof(EVENT_REPORT));
351       free(evt_ptr);
352       break;
353
354     case EVEL_DOMAIN_SERVICE:
355       EVEL_DEBUG("Event is a Service Event at %lp", evt_ptr);
356       evel_free_service((EVENT_SERVICE *)evt_ptr);
357       memset(evt_ptr, 0, sizeof(EVENT_SERVICE));
358       free(evt_ptr);
359       break;
360
361     case EVEL_DOMAIN_SIGNALING:
362       EVEL_DEBUG("Event is a Signaling at %lp", evt_ptr);
363       evel_free_signaling((EVENT_SIGNALING *)evt_ptr);
364       memset(evt_ptr, 0, sizeof(EVENT_SIGNALING));
365       free(evt_ptr);
366       break;
367
368     case EVEL_DOMAIN_STATE_CHANGE:
369       EVEL_DEBUG("Event is a State Change at %lp", evt_ptr);
370       evel_free_state_change((EVENT_STATE_CHANGE *)evt_ptr);
371       memset(evt_ptr, 0, sizeof(EVENT_STATE_CHANGE));
372       free(evt_ptr);
373       break;
374
375     case EVEL_DOMAIN_SYSLOG:
376       EVEL_DEBUG("Event is a Syslog at %lp", evt_ptr);
377       evel_free_syslog((EVENT_SYSLOG *)evt_ptr);
378       memset(evt_ptr, 0, sizeof(EVENT_SYSLOG));
379       free(evt_ptr);
380       break;
381
382     case EVEL_DOMAIN_OTHER:
383       EVEL_DEBUG("Event is an Other at %lp", evt_ptr);
384       evel_free_other((EVENT_OTHER *)evt_ptr);
385       memset(evt_ptr, 0, sizeof(EVENT_OTHER));
386       free(evt_ptr);
387       break;
388
389     default:
390       EVEL_ERROR("Unexpected event domain (%d)", evt_ptr->event_domain);
391       assert(0);
392     }
393   }
394   EVEL_EXIT();
395 }