Initial OpenECOMP Demo commit
[demo.git] / vnfs / VES / code / evel_library / evel_reporting_measurement.c
1 /**************************************************************************//**
2  * @file
3  * Implementation of EVEL functions relating to the Measurement for VF
4  * Reporting event.
5  *
6  * @note  This is an experimental event tytpe and does not form part of the
7  *        currently approved AT&T event schema.  It is intended to allow a
8  *        less-onerous event reporting mechanism because it avoids having to
9  *        return all the platform statistics which are mandatory in the
10  *        **measurementsForVfScaling** event.
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
48 #include "evel.h"
49 #include "evel_internal.h"
50 #include "evel_throttle.h"
51
52 /**************************************************************************//**
53  * Create a new Report event.
54  *
55  * @note    The mandatory fields on the Report must be supplied to this
56  *          factory function and are immutable once set.  Optional fields have
57  *          explicit setter functions, but again values may only be set once so
58  *          that the Report has immutable properties.
59  *
60  * @param   measurement_interval
61
62  * @returns pointer to the newly manufactured ::EVENT_REPORT.  If the event is
63  *          not used (i.e. posted) it must be released using ::evel_free_event.
64  * @retval  NULL  Failed to create the event.
65  *****************************************************************************/
66 EVENT_REPORT * evel_new_report(double measurement_interval)
67 {
68   EVENT_REPORT * report = NULL;
69
70   EVEL_ENTER();
71
72   /***************************************************************************/
73   /* Check preconditions.                                                    */
74   /***************************************************************************/
75   assert(measurement_interval >= 0.0);
76
77   /***************************************************************************/
78   /* Allocate the report.                                                    */
79   /***************************************************************************/
80   report = malloc(sizeof(EVENT_REPORT));
81   if (report == NULL)
82   {
83     log_error_state("Out of memory for Report");
84     goto exit_label;
85   }
86   memset(report, 0, sizeof(EVENT_REPORT));
87   EVEL_DEBUG("New report is at %lp", report);
88
89   /***************************************************************************/
90   /* Initialize the header & the report fields.                              */
91   /***************************************************************************/
92   evel_init_header(&report->header);
93   report->header.event_domain = EVEL_DOMAIN_REPORT;
94   report->measurement_interval = measurement_interval;
95
96   dlist_initialize(&report->feature_usage);
97   dlist_initialize(&report->measurement_groups);
98   report->major_version = EVEL_REPORT_MAJOR_VERSION;
99   report->minor_version = EVEL_REPORT_MINOR_VERSION;
100
101 exit_label:
102   EVEL_EXIT();
103   return report;
104 }
105
106 /**************************************************************************//**
107  * Set the Event Type property of the Report.
108  *
109  * @note  The property is treated as immutable: it is only valid to call
110  *        the setter once.  However, we don't assert if the caller tries to
111  *        overwrite, just ignoring the update instead.
112  *
113  * @param report Pointer to the Report.
114  * @param type        The Event Type to be set. ASCIIZ string. The caller
115  *                    does not need to preserve the value once the function
116  *                    returns.
117  *****************************************************************************/
118 void evel_report_type_set(EVENT_REPORT * report,
119                           const char * const type)
120 {
121   EVEL_ENTER();
122
123   /***************************************************************************/
124   /* Check preconditions and call evel_header_type_set.                      */
125   /***************************************************************************/
126   assert(report != NULL);
127   assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
128   evel_header_type_set(&report->header, type);
129
130   EVEL_EXIT();
131 }
132
133 /**************************************************************************//**
134  * Add a Feature usage value name/value pair to the Report.
135  *
136  * The name is null delimited ASCII string.  The library takes
137  * a copy so the caller does not have to preserve values after the function
138  * returns.
139  *
140  * @param report          Pointer to the report.
141  * @param feature         ASCIIZ string with the feature's name.
142  * @param utilization     Utilization of the feature.
143  *****************************************************************************/
144 void evel_report_feature_use_add(EVENT_REPORT * report,
145                                  char * feature,
146                                  int utilization)
147 {
148   MEASUREMENT_FEATURE_USE * feature_use = NULL;
149   EVEL_ENTER();
150
151   /***************************************************************************/
152   /* Check assumptions.                                                      */
153   /***************************************************************************/
154   assert(report != NULL);
155   assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
156   assert(feature != NULL);
157   assert(utilization >= 0);
158
159   /***************************************************************************/
160   /* Allocate a container for the value and push onto the list.              */
161   /***************************************************************************/
162   EVEL_DEBUG("Adding Feature=%s Use=%d", feature, utilization);
163   feature_use = malloc(sizeof(MEASUREMENT_FEATURE_USE));
164   assert(feature_use != NULL);
165   memset(feature_use, 0, sizeof(MEASUREMENT_FEATURE_USE));
166   feature_use->feature_id = strdup(feature);
167   assert(feature_use->feature_id != NULL);
168   feature_use->feature_utilization = utilization;
169
170   dlist_push_last(&report->feature_usage, feature_use);
171
172   EVEL_EXIT();
173 }
174
175 /**************************************************************************//**
176  * Add a Additional Measurement value name/value pair to the Report.
177  *
178  * The name is null delimited ASCII string.  The library takes
179  * a copy so the caller does not have to preserve values after the function
180  * returns.
181  *
182  * @param report   Pointer to the report.
183  * @param group    ASCIIZ string with the measurement group's name.
184  * @param name     ASCIIZ string containing the measurement's name.
185  * @param value    ASCIIZ string containing the measurement's value.
186  *****************************************************************************/
187 void evel_report_custom_measurement_add(EVENT_REPORT * report,
188                                         const char * const group,
189                                         const char * const name,
190                                         const char * const value)
191 {
192   MEASUREMENT_GROUP * measurement_group = NULL;
193   CUSTOM_MEASUREMENT * measurement = NULL;
194   DLIST_ITEM * item = NULL;
195   EVEL_ENTER();
196
197   /***************************************************************************/
198   /* Check assumptions.                                                      */
199   /***************************************************************************/
200   assert(report != NULL);
201   assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
202   assert(group != NULL);
203   assert(name != NULL);
204   assert(value != NULL);
205
206   /***************************************************************************/
207   /* Allocate a container for the name/value pair.                           */
208   /***************************************************************************/
209   EVEL_DEBUG("Adding Measurement Group=%s Name=%s Value=%s",
210               group, name, value);
211   measurement = malloc(sizeof(CUSTOM_MEASUREMENT));
212   assert(measurement != NULL);
213   memset(measurement, 0, sizeof(CUSTOM_MEASUREMENT));
214   measurement->name = strdup(name);
215   assert(measurement->name != NULL);
216   measurement->value = strdup(value);
217   assert(measurement->value != NULL);
218
219   /***************************************************************************/
220   /* See if we have that group already.                                      */
221   /***************************************************************************/
222   item = dlist_get_first(&report->measurement_groups);
223   while (item != NULL)
224   {
225     measurement_group = (MEASUREMENT_GROUP *) item->item;
226     assert(measurement_group != NULL);
227
228     EVEL_DEBUG("Got measurement group %s", measurement_group->name);
229     if (strcmp(group, measurement_group->name) == 0)
230     {
231       EVEL_DEBUG("Found existing Measurement Group");
232       break;
233     }
234     item = dlist_get_next(item);
235   }
236
237   /***************************************************************************/
238   /* If we didn't have the group already, create it.                         */
239   /***************************************************************************/
240   if (item == NULL)
241   {
242     EVEL_DEBUG("Creating new Measurement Group");
243     measurement_group = malloc(sizeof(MEASUREMENT_GROUP));
244     assert(measurement_group != NULL);
245     memset(measurement_group, 0, sizeof(MEASUREMENT_GROUP));
246     measurement_group->name = strdup(group);
247     assert(measurement_group->name != NULL);
248     dlist_initialize(&measurement_group->measurements);
249     dlist_push_last(&report->measurement_groups, measurement_group);
250   }
251
252   /***************************************************************************/
253   /* If we didn't have the group already, create it.                         */
254   /***************************************************************************/
255   dlist_push_last(&measurement_group->measurements, measurement);
256
257   EVEL_EXIT();
258 }
259
260 /**************************************************************************//**
261  * Encode the report as a JSON report.
262  *
263  * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
264  * @param event         Pointer to the ::EVENT_HEADER to encode.
265  *****************************************************************************/
266 void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf,
267                              EVENT_REPORT * event)
268 {
269   MEASUREMENT_FEATURE_USE * feature_use = NULL;
270   MEASUREMENT_GROUP * measurement_group = NULL;
271   CUSTOM_MEASUREMENT * custom_measurement = NULL;
272   DLIST_ITEM * item = NULL;
273   DLIST_ITEM * nested_item = NULL;
274
275   EVEL_ENTER();
276
277   /***************************************************************************/
278   /* Check preconditions.                                                    */
279   /***************************************************************************/
280   assert(event != NULL);
281   assert(event->header.event_domain == EVEL_DOMAIN_REPORT);
282
283   evel_json_encode_header(jbuf, &event->header);
284   evel_json_open_named_object(jbuf, "measurementsForVfReportingFields");
285   evel_enc_kv_double(jbuf, "measurementInterval", event->measurement_interval);
286
287   /***************************************************************************/
288   /* Feature Utilization list.                                               */
289   /***************************************************************************/
290   evel_json_checkpoint(jbuf);
291   if (evel_json_open_opt_named_list(jbuf, "featureUsageArray"))
292   {
293     bool item_added = false;
294
295     item = dlist_get_first(&event->feature_usage);
296     while (item != NULL)
297     {
298       feature_use = (MEASUREMENT_FEATURE_USE*) item->item;
299       assert(feature_use != NULL);
300
301       if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
302                                           "featureUsageArray",
303                                           feature_use->feature_id))
304       {
305         evel_json_open_object(jbuf);
306         evel_enc_kv_string(jbuf, "featureIdentifier", feature_use->feature_id);
307         evel_enc_kv_int(
308           jbuf, "featureUtilization", feature_use->feature_utilization);
309         evel_json_close_object(jbuf);
310         item_added = true;
311       }
312       item = dlist_get_next(item);
313     }
314     evel_json_close_list(jbuf);
315
316     /*************************************************************************/
317     /* If we've not written anything, rewind to before we opened the list.   */
318     /*************************************************************************/
319     if (!item_added)
320     {
321       evel_json_rewind(jbuf);
322     }
323   }
324
325   /***************************************************************************/
326   /* Additional Measurement Groups list.                                     */
327   /***************************************************************************/
328   evel_json_checkpoint(jbuf);
329   if (evel_json_open_opt_named_list(jbuf, "additionalMeasurements"))
330   {
331     bool item_added = false;
332
333     item = dlist_get_first(&event->measurement_groups);
334     while (item != NULL)
335     {
336       measurement_group = (MEASUREMENT_GROUP *) item->item;
337       assert(measurement_group != NULL);
338
339       if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
340                                           "additionalMeasurements",
341                                           measurement_group->name))
342       {
343         evel_json_open_object(jbuf);
344         evel_enc_kv_string(jbuf, "name", measurement_group->name);
345         evel_json_open_named_list(jbuf, "measurements");
346
347         /*********************************************************************/
348         /* Measurements list.                                                */
349         /*********************************************************************/
350         nested_item = dlist_get_first(&measurement_group->measurements);
351         while (nested_item != NULL)
352         {
353           custom_measurement = (CUSTOM_MEASUREMENT *) nested_item->item;
354           assert(custom_measurement != NULL);
355
356           evel_json_open_object(jbuf);
357           evel_enc_kv_string(jbuf, "name", custom_measurement->name);
358           evel_enc_kv_string(jbuf, "value", custom_measurement->value);
359           evel_json_close_object(jbuf);
360           nested_item = dlist_get_next(nested_item);
361         }
362         evel_json_close_list(jbuf);
363         evel_json_close_object(jbuf);
364         item_added = true;
365       }
366       item = dlist_get_next(item);
367     }
368     evel_json_close_list(jbuf);
369
370     /*************************************************************************/
371     /* If we've not written anything, rewind to before we opened the list.   */
372     /*************************************************************************/
373     if (!item_added)
374     {
375       evel_json_rewind(jbuf);
376     }
377   }
378
379   /***************************************************************************/
380   /* Although optional, we always generate the version.  Note that this      */
381   /* closes the object, too.                                                 */
382   /***************************************************************************/
383   evel_enc_version(jbuf,
384                    "measurementFieldsVersion",
385                    event->major_version,
386                    event->major_version);
387   evel_json_close_object(jbuf);
388
389   EVEL_EXIT();
390 }
391
392 /**************************************************************************//**
393  * Free a Report.
394  *
395  * Free off the Report supplied.  Will free all the contained allocated memory.
396  *
397  * @note It does not free the Report itself, since that may be part of a
398  * larger structure.
399  *****************************************************************************/
400 void evel_free_report(EVENT_REPORT * event)
401 {
402   MEASUREMENT_FEATURE_USE * feature_use = NULL;
403   MEASUREMENT_GROUP * measurement_group = NULL;
404   CUSTOM_MEASUREMENT * custom_measurement = NULL;
405
406   EVEL_ENTER();
407
408   /***************************************************************************/
409   /* Check preconditions.  As an internal API we don't allow freeing NULL    */
410   /* events as we do on the public API.                                      */
411   /***************************************************************************/
412   assert(event != NULL);
413   assert(event->header.event_domain == EVEL_DOMAIN_REPORT);
414
415   /***************************************************************************/
416   /* Free all internal strings then the header itself.                       */
417   /***************************************************************************/
418   feature_use = dlist_pop_last(&event->feature_usage);
419   while (feature_use != NULL)
420   {
421     EVEL_DEBUG("Freeing Feature use Info (%s)", feature_use->feature_id);
422     free(feature_use->feature_id);
423     free(feature_use);
424     feature_use = dlist_pop_last(&event->feature_usage);
425   }
426   measurement_group = dlist_pop_last(&event->measurement_groups);
427   while (measurement_group != NULL)
428   {
429     EVEL_DEBUG("Freeing Measurement Group (%s)", measurement_group->name);
430
431     custom_measurement = dlist_pop_last(&measurement_group->measurements);
432     while (custom_measurement != NULL)
433     {
434       EVEL_DEBUG("Freeing mesaurement (%s)", custom_measurement->name);
435
436       free(custom_measurement->name);
437       free(custom_measurement->value);
438       free(custom_measurement);
439       custom_measurement = dlist_pop_last(&measurement_group->measurements);
440     }
441
442     free(measurement_group->name);
443     free(measurement_group);
444     measurement_group = dlist_pop_last(&event->measurement_groups);
445   }
446
447   evel_free_header(&event->header);
448
449   EVEL_EXIT();
450 }