Added documentation directory compliant with LF guidelines
[ric-app/admin.git] / src / protector-plugin / admission_policy.cc
1 /*
2 ==================================================================================
3
4         Copyright (c) 2018-2019 AT&T Intellectual Property.
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20
21 #include "admission_policy.hpp"
22 admission::admission (std::string policy_schema_file, std::string samples_file,  std::string metrics_schema_file, unsigned int num_instances, bool report_only){
23   bool res;
24   
25   if (num_instances == 0){
26     throw std::runtime_error("Error ! Number of instances of admission_policy protector pluging must be > 0");
27   }
28   
29   std::string response;
30   std::string buffer;
31   std::string error_string;
32   
33   std::vector<TrieNode> config_schema_path;
34   
35   config_schema_path.clear();
36
37   // path to node in schema to process policy request
38   config_schema_path.emplace_back("controls");
39   config_schema_path.emplace_back((int)0);
40   config_schema_path.emplace_back("message_receives_payload_schema");
41   config_schema_path[0].add_child(&config_schema_path[1]);
42   config_schema_path[1].add_child(&config_schema_path[2]);
43   
44   set_policy_req_obj.load_schema(policy_schema_file, &config_schema_path[0]);
45   // mdclog_write(MDCLOG_INFO, "Loaded schema for set Policy request");
46   
47   //path to node in schema  to process policy response
48   config_schema_path.clear();
49   config_schema_path.emplace_back("controls");
50   config_schema_path.emplace_back(0);
51   config_schema_path.emplace_back("message_sends_payload_schema");
52   config_schema_path[0].add_child(&config_schema_path[1]);
53   config_schema_path[1].add_child(&config_schema_path[2]);
54
55   set_policy_resp_obj.load_schema(policy_schema_file, &config_schema_path[0]);
56   mdclog_write(MDCLOG_INFO, "Loaded schema for set Policy response");
57   
58   // load sample response 
59   config_schema_path.clear();
60   config_schema_path.emplace_back("message_sends_example");
61   
62   set_policy_resp_obj.load_buffer(samples_file, &config_schema_path[0]);
63   
64   // verify that our sample conforms to the schema ...
65   buffer = set_policy_resp_obj.get_buffer();
66   if (! set_policy_resp_obj.is_valid(buffer.c_str(), buffer.length(), response)){
67     std::stringstream ss;
68     ss << "Error ! Sample loaded for SET policy response = " << buffer << " from file " << samples_file << " not valid. Reason = " << response;
69     throw std::runtime_error(ss.str());
70   }
71   mdclog_write(MDCLOG_INFO, "Verified  sample for set Policy response");
72   
73   // path to node in schema to  respond to get policy (current same as set policy)
74   config_schema_path.clear();
75   config_schema_path.emplace_back("controls");
76   config_schema_path.emplace_back(0);
77   config_schema_path.emplace_back("message_receives_payload_schema");
78   config_schema_path[0].add_child(&config_schema_path[1]);
79   config_schema_path[1].add_child(&config_schema_path[2]);
80
81   get_policy_resp_obj.load_schema(policy_schema_file, &config_schema_path[0]);
82   mdclog_write(MDCLOG_INFO, "Loaded schema for get  Policy response");
83   
84
85   // sample to respond to get policy
86   config_schema_path.clear();
87   config_schema_path.emplace_back("message_receives_example");
88
89   get_policy_resp_obj.load_buffer(samples_file, &config_schema_path[0]);
90   
91   // verify that our sample conforms to schema
92   buffer = get_policy_resp_obj.get_buffer();
93   if (! get_policy_resp_obj.is_valid(buffer.c_str(), buffer.length(), response)){
94     std::stringstream ss;
95     ss << "Error ! Sample loaded for GET policy response = " << buffer << " from file " << samples_file << " not valid. Reason = " << response;
96     throw std::runtime_error(ss.str());
97
98   }
99   
100   mdclog_write(MDCLOG_INFO, "Verified sample for get Policy response");
101   
102   // schema & sample for metrics
103   metrics_obj.load_schema(metrics_schema_file); 
104   mdclog_write(MDCLOG_INFO, "Loaded schema  for ves metrics");
105  
106   config_schema_path.clear();
107   config_schema_path.emplace_back("metrics");
108
109   metrics_obj.load_buffer(samples_file, &config_schema_path[0]);  
110   
111   // verify sample conforms to schema
112   buffer = metrics_obj.get_buffer();
113   if (! metrics_obj.is_valid(buffer.c_str(), buffer.length(), response)){
114     std::stringstream ss;
115     ss << "Error ! Sample loaded for VES = " << buffer << " from file " << samples_file << " not valid. Reason = " << response;
116     throw std::runtime_error(ss.str());
117   }
118   
119   mdclog_write(MDCLOG_INFO, "Verified sample for metrics");
120   
121   setPolicyVars();
122   
123   
124   //instantiate the core policy object
125   for(unsigned int i = 0; i < num_instances; i++){
126     instantiate_protector_plugin(report_only);
127   }
128   
129 };
130
131 void admission::instantiate_protector_plugin(bool mode){
132   _plugin_instances.emplace_back(bool(current_config["enforce"]), current_config["window_length"], current_config["trigger_threshold"], current_config["blocking_rate"], mode);
133 }
134
135 admission::~admission(void){
136   prev_values.clear();
137   curr_values.clear();
138   policy_vars.clear();
139   set_policy_response.clear();
140   get_policy_response.clear();
141   metric_responses.clear();
142   policy_pointer.clear();
143 }
144
145
146 std::string admission::getName(void){
147   return std::string("admission control policy");
148 }
149
150 void admission::setPolicyVars(void){
151
152
153   // keys in request to set policy
154   policy_vars.emplace_back("enforce");
155   policy_vars.emplace_back("window_length");
156   policy_vars.emplace_back("blocking_rate");
157   policy_vars.emplace_back("trigger_threshold");
158
159   
160   // keys in response to set policy
161   set_policy_response.emplace_back("status");
162   set_policy_response.emplace_back("message");
163
164   
165   policy_pointer.push_back(&policy_vars[0]);
166   policy_pointer.push_back(&policy_vars[1]);
167   policy_pointer.push_back(&policy_vars[2]);
168   policy_pointer.push_back(&policy_vars[3]);
169
170
171   // keys in metric response
172   metric_responses.emplace_back("event");  // 0
173   metric_responses.emplace_back("commonEventHeader");  // 1
174   metric_responses.emplace_back("measurementFields"); // 2
175   metric_responses.emplace_back("additionalFields");  // 3
176   metric_responses.emplace_back("SgNB Request Rate");  // 4
177   metric_responses.emplace_back("SgNB Accept Rate");  // 5
178   metric_responses.emplace_back("startEpochMicrosec"); // 6
179   metric_responses.emplace_back("measurementInterval"); // 7
180   metric_responses.emplace_back("lastEpochMicrosec");//8
181   //metric_responses.emplace_back("TS"); //9
182   
183   metric_responses[0].add_child(&metric_responses[1]);
184   metric_responses[0].add_child(&metric_responses[2]);
185
186   metric_responses[1].add_child(&metric_responses[6]);  
187   metric_responses[1].add_child(&metric_responses[8]);
188
189   metric_responses[2].add_child(&metric_responses[3]);
190   metric_responses[2].add_child(&metric_responses[7]);
191
192   metric_responses[3].add_child(&metric_responses[4]);
193   metric_responses[3].add_child(&metric_responses[5]);
194   //metric_responses[3].add_child(&metric_responses[9]);
195
196   // default config map for the policy object
197   current_config.insert(std::pair<std::string, int>("enforce", 1));
198   current_config.insert(std::pair<std::string, int>("window_length", 60));
199   current_config.insert(std::pair<std::string, int>("blocking_rate", 1));
200   current_config.insert(std::pair<std::string, int>("trigger_threshold", 1));
201   
202   prev_config = current_config;
203
204   auto ts = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now());
205   auto epoch = ts.time_since_epoch();
206   auto val = std::chrono::duration_cast<std::chrono::microseconds>(epoch);
207   prev_time_stamp = val.count();
208   prev_values.push_back(0);
209   prev_values.push_back(0);
210   curr_values = prev_values;
211 }
212
213 protector * admission::get_protector_instance(unsigned int index){
214   if (index > _plugin_instances.size() -1){
215     mdclog_write(MDCLOG_ERR, "%s, %d: Error . Requested index %u exceeds number of plugin instances %u", __FILE__, __LINE__, index, _plugin_instances.size());
216     return NULL;
217   }
218   else{
219     return &_plugin_instances[index];
220   }
221 };
222
223
224
225 bool admission::setPolicy(const char * message, int message_length, std::string & response){
226
227   // Get the configuration
228   std::vector<TrieNode*> available_keys;
229   std::vector<TrieNode*> roots;
230   bool res;
231   
232   std::vector<TrieNode*>resp_pointer;
233   resp_pointer.push_back(&set_policy_response[0]);
234   resp_pointer.push_back(&set_policy_response[1]);
235   
236   std::string local_response;
237   for(unsigned int i = 0; i < policy_vars.size(); i++){
238     int res = set_policy_req_obj.get_values(message, message_length, local_response, &policy_vars[i],  available_keys);
239     if (res != 0 ){
240       setError(local_response);
241       set_policy_response[0].set_value("FAIL");
242       set_policy_response[1].set_value(local_response);
243       set_policy_resp_obj.set_values(response, resp_pointer);
244    
245       return false;
246     }
247   }
248   
249   if ( available_keys.size() == 0){
250     local_response  = "No Keys were found";
251     setError(local_response);
252     set_policy_response[0].set_value("FAIL");
253     set_policy_response[1].set_value(local_response);
254     
255     set_policy_resp_obj.set_values(response,resp_pointer);
256     return false;
257   }
258                                      
259
260   // Get new config
261   prev_config = current_config;
262   
263   for(std::vector<TrieNode *>::iterator it = available_keys.begin(); it != available_keys.end(); ++it){
264     DataContainer const * id = (*it)->get_id();
265     DataContainer const * val = (*it)->get_value();
266     auto e = current_config.find(id->value.s.c_str());
267     if (e != current_config.end()){
268       e->second = val->value.i;
269     }
270
271   }
272
273   // Note : xapp schema specifies window be in 'minutes'. Sliding window implementation maintains in seconds, hence multiply by 60
274   current_config["window_length"] *= 60;
275
276   // Apply the config
277   res= true;
278   for(std::vector<protector>::iterator it_p = _plugin_instances.begin(); it_p != _plugin_instances.end(); ++it_p){
279     
280     res = (*it_p).configure( bool(current_config["enforce"]), current_config["window_length"], current_config["trigger_threshold"],  current_config["blocking_rate"]);
281     if (!res){
282       mdclog_write(MDCLOG_ERR, "Error ::%s, %d :: Could not configure plugin\n", __FILE__, __LINE__);
283       set_policy_response[0].set_value("FAIL");
284       set_policy_response[1].set_value("Could not apply configuration");
285       break;
286     }
287   }
288
289   if (res){
290     set_policy_response[0].set_value("SUCCESS");
291     set_policy_response[1].set_value("configuration applied");
292   }
293   
294   set_policy_resp_obj.set_values(response,resp_pointer);
295   return true;
296   
297 };
298   
299 bool admission::getPolicy(const char * message, int message_length, std::string & response){
300
301   // Note : by same token, when returning sliding window length : translate to
302   // minutes
303   policy_vars[0].set_value(bool(current_config["enforce"]));
304   policy_vars[1].set_value((int)( (double)current_config["window_length"]/60.0));
305   policy_vars[2].set_value(current_config["blocking_rate"]);
306   policy_vars[3].set_value(current_config["trigger_threshold"]);
307
308   int res = get_policy_resp_obj.set_values(response, policy_pointer);
309   return true;
310                                                                        
311 }
312
313
314 int admission::getMetrics(std::string & response){
315   std::vector<TrieNode *> metric_pointers;
316   metric_pointers.push_back(&metric_responses[0]);
317
318   auto ts = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now());
319   auto epoch = ts.time_since_epoch();
320   auto val_ms = std::chrono::duration_cast<std::chrono::microseconds>(epoch);
321   auto val_s = std::chrono::duration_cast<std::chrono::seconds>(epoch);
322   
323   long int  current_time_stamp = val_ms.count();
324   long int current_time = val_s.count();
325   long int interval = current_time_stamp - prev_time_stamp;
326
327
328   curr_values[0] = _plugin_instances[0].get_requests();
329   curr_values[1] =  _plugin_instances[0].get_rejects();
330
331   //curr_values[0] = rand()%100 + prev_values[0];
332   //curr_values[1] = rand()%20 + prev_values[1];
333  
334   //std::cout <<" Accept counter = " << curr_values[0]<< " Reject counter = " << curr_values[1] << " Request Count = " <<  (curr_values[0] - prev_values[0]) << " Reject count = " << curr_values[1] - prev_values[1] << std::endl;
335
336   metric_responses[4].set_value(std::to_string(curr_values[0] - prev_values[0]));
337   metric_responses[5].set_value(std::to_string((curr_values[0] - prev_values[0]) - (curr_values[1] - prev_values[1])));
338   metric_responses[6].set_value(prev_time_stamp);
339   metric_responses[8].set_value(current_time_stamp);
340   metric_responses[7].set_value(interval);
341   //metric_responses[9].set_value(current_time);
342   
343   prev_values = curr_values;
344   prev_time_stamp = current_time_stamp;
345   int res = metrics_obj.set_values(response, metric_pointers);
346
347   return res;
348   
349 }