LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-analytics/contrail-collector - ruleeng.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 522 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include <sstream>
       7             : #include <exception>
       8             : #include <cstdlib>
       9             : #include <algorithm>
      10             : #include <string>
      11             : #include <boost/lexical_cast.hpp>
      12             : #include <boost/assign/list_of.hpp>
      13             : #include <boost/tuple/tuple.hpp>
      14             : #include <base/util.h>
      15             : #include <boost/ptr_container/ptr_vector.hpp>
      16             : #include <base/logging.h>
      17             : #include <sandesh/sandesh_trace.h>
      18             : #include <sandesh/sandesh_message_builder.h>
      19             : #include <sandesh/protocol/TXMLProtocol.h>
      20             : #include "ruleparser/ruleglob.h"
      21             : #include "db_handler.h"
      22             : #include "OpServerProxy.h"
      23             : #include <analytics/collector_uve_types.h>
      24             : #include <analytics/viz_constants.h>
      25             : #include "ruleeng.h"
      26             : #include "stat_walker.h"
      27             : 
      28             : using std::string;
      29             : using std::vector;
      30             : using std::map;
      31             : using std::pair;
      32             : using std::make_pair;
      33             : using boost::tuple;
      34             : using boost::tuples::make_tuple;
      35             : using boost::ptr_vector;
      36             : 
      37             : using namespace contrail::sandesh::protocol;
      38             : 
      39             : int Ruleeng::RuleBuilderID = 0;
      40             : int Ruleeng::RuleWorkerID = 0;
      41             : 
      42             : SandeshTraceBufferPtr UVETraceBuf(SandeshTraceBufferCreate("UveTrace", 25000));
      43             : 
      44           0 : Ruleeng::Ruleeng(DbHandlerPtr db_handler, OpServerProxy *osp) :
      45           0 :     db_handler_(db_handler), osp_(osp), rulelist_(new t_rulelist()) {
      46           0 : }
      47             : 
      48           0 : Ruleeng::~Ruleeng() { 
      49           0 :     delete rulelist_;
      50           0 : }
      51             : 
      52           0 : void Ruleeng::Init() {
      53           0 :     LOG(DEBUG, "Ruleeng::" << __func__ << " Begin");
      54           0 :     DbHandler::RuleMap rulemap;
      55             : 
      56           0 :     if (db_handler_) {
      57           0 :         db_handler_->GetRuleMap(rulemap);
      58           0 :         DbHandler::RuleMap::iterator iter;
      59             : 
      60           0 :         for (iter = rulemap.begin(); iter != rulemap.end(); iter++) {
      61           0 :             Buildrules((*iter).first, (*iter).second);
      62             :         }
      63             :     }
      64           0 :     LOG(DEBUG, "Ruleeng::" << __func__ << " Done");
      65           0 : }
      66             : 
      67           0 : bool Ruleeng::Buildrules(const std::string& rulesrc, const std::string& rulebuf) { 
      68           0 :     Builder *task = new Builder(this, rulesrc, rulebuf);
      69           0 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
      70           0 :     scheduler->Enqueue(task);
      71             : 
      72           0 :     return true;
      73             : }
      74             : 
      75           0 : bool Ruleeng::Parserules(char *base, size_t sz) { 
      76           0 :     parse(rulelist_, base, sz);
      77             : 
      78           0 :     return true;
      79             : }
      80             : 
      81           0 : bool Ruleeng::Parserules(const char *bytes, int len) { 
      82           0 :     parse(rulelist_, bytes, len);
      83             : 
      84           0 :     return true;
      85             : }
      86             : 
      87           0 : bool Ruleeng::rule_present(const VizMsg *vmsgp) {
      88           0 :     t_rulemsgtype msgtype(vmsgp->msg->GetMessageType());
      89             : 
      90           0 :     const SandeshHeader &header(vmsgp->msg->GetHeader());
      91           0 :     if (header.__isset.Context) {
      92           0 :         msgtype.has_context_ = true;
      93           0 :         msgtype.context_ = header.Context;
      94             :     }
      95             : 
      96           0 :     return rulelist_->rule_present(msgtype);
      97           0 : }
      98             : 
      99             : 
     100           0 : void Ruleeng::remove_identifier(const pugi::xml_node &parent) {
     101           0 :     for (pugi::xml_node node = parent.first_child(); node;
     102           0 :          node = node.next_sibling()) {
     103           0 :         node.remove_attribute("identifier");
     104           0 :         remove_identifier(node);
     105             :     }
     106           0 : }
     107             : 
     108           0 : static bool ParseNodeImpl(DbHandler::Var& sample,
     109             :         const string& attype, const pugi::xml_node& node) {
     110           0 :     if (attype == "string") {
     111           0 :         std::string val(node.child_value());
     112           0 :         TXMLProtocol::unescapeXMLControlChars(val);
     113           0 :         sample = val;
     114           0 :     } else if (attype == "double") {   
     115           0 :         sample = (double) strtod(node.child_value(), NULL);
     116           0 :     } else if ((attype == "u16") ||  (attype == "u32") || (attype == "u64")) {
     117           0 :         sample = (uint64_t) strtoul(node.child_value(), NULL, 10);
     118           0 :     } else if (attype == "set" || attype == "list") {
     119           0 :         pugi::xml_node set;
     120           0 :         if (attype == "set") {
     121           0 :             set = node.child("set");
     122             :         } else {
     123           0 :             set = node.child("list");
     124             :         }
     125           0 :         if (strcmp(set.attribute("type").value(),"string") != 0) {
     126           0 :             return false;
     127             :         }
     128           0 :         std::vector<std::string> set_value;
     129           0 :         for (pugi::xml_node set_elem = set.first_child(); set_elem;
     130           0 :                 set_elem = set_elem.next_sibling()) {
     131           0 :             std::string elem_value = set_elem.child_value();
     132           0 :             TXMLProtocol::unescapeXMLControlChars(elem_value);
     133           0 :             set_value.push_back(elem_value);
     134           0 :         }
     135           0 :         sample = set_value;
     136           0 :     } else if (attype == "map") {
     137           0 :         pugi::xml_node map_node = node.child("map");
     138           0 :         if (strcmp(map_node.attribute("key").value(), "string") != 0) {
     139           0 :             return false;
     140             :         }
     141           0 :         if (strcmp(map_node.attribute("value").value(), "string") != 0) {
     142           0 :             return false;
     143             :         }
     144           0 :         std::map<std::string, std::string> map_value;
     145           0 :         for (pugi::xml_node map_key = map_node.first_child(); map_key;
     146           0 :             map_key = map_key.next_sibling().next_sibling()) {
     147           0 :             std::ostringstream key_val;
     148             :             std::pair<std::string, string> map_elem =
     149           0 :                 std::make_pair(std::string(map_key.child_value()),
     150           0 :                     std::string(map_key.next_sibling().child_value()));
     151           0 :             map_value.insert(map_elem);
     152           0 :         }
     153           0 :         sample = map_value;
     154           0 :     } else {
     155           0 :         return false;
     156             :     }
     157           0 :     return true;
     158             : }
     159             : 
     160           0 : static DbHandler::Var ParseNode(const pugi::xml_node& node, bool silent = false) {
     161           0 :     DbHandler::Var sample;
     162             : 
     163           0 :     if (node.empty()) {
     164           0 :         LOG(ERROR, __func__ << "Parsing Empty node");
     165           0 :         return sample;
     166             :     }
     167           0 :     string attype = node.attribute("type").value();
     168           0 :     if (!ParseNodeImpl(sample, attype, node)) {
     169           0 :         if (!silent)
     170           0 :             LOG(ERROR, __func__ << " Bad Stat Type " << attype <<
     171             :                 " for attr " << node.name());
     172             :     }
     173           0 :     return sample;
     174           0 : }
     175             : 
     176             : // Dom Elements are pair
     177             : // First member is a variant; either xml_node (struct) or Var (basic type)
     178             : // Second member is a key, for the map case
     179             : typedef boost::variant<pugi::xml_node, DbHandler::Var> ElemVar;
     180             : typedef std::pair<ElemVar, string> ElemT; 
     181             : 
     182             : class DomChildVisitor : public boost::static_visitor<> {
     183             :   public:
     184           0 :     void operator()(const pugi::xml_node& node) {
     185           0 :         parent = node;
     186           0 :     }
     187           0 :     void operator()(const DbHandler::Var& dv) {
     188           0 :     }
     189             : 
     190             :     pugi::xml_node parent;
     191             : 
     192           0 :     void GetResult(const string& sub, pugi::xml_node& node) {
     193           0 :         if (!parent) {
     194           0 :             node = parent;
     195             :         } else {
     196           0 :             node = parent.child(sub.c_str()); 
     197             :         }
     198           0 :     }
     199             : };
     200             : 
     201           0 : static bool ParseDomTags(const std::string& tstr,
     202             :         std::vector<std::string> *toptags,
     203             :         const ptr_vector<tuple<string,ElemT> >* elem_chain,
     204             :         StatWalker::TagMap *tagmap) {
     205             :     size_t pos;
     206           0 :     size_t npos = 0;
     207             : 
     208             :     // If the tags string is empty, there's nothing to parse
     209           0 :     if (tstr.empty()) return true;
     210             : 
     211             :     do {
     212           0 :         if (npos)
     213           0 :             pos = npos+1;
     214             :         else
     215           0 :             pos = 0;
     216             :         
     217           0 :         npos = tstr.find(',' , pos);
     218           0 :         string term;
     219           0 :         if (npos == string::npos)
     220           0 :             term = tstr.substr(pos, string::npos);
     221             :         else 
     222           0 :             term = tstr.substr(pos, npos - pos);
     223             : 
     224             :         // Separating this term into a prefix and suffix
     225             :         // Prefix may not be present
     226           0 :         size_t spos = term.find(':');
     227           0 :         string pterm, sterm;
     228             : 
     229           0 :         if (spos == string::npos) {
     230             :             // Single Tag case
     231           0 :             sterm = term;
     232             :         } else {
     233             :             // Double Tag case 
     234           0 :             pterm = term.substr(0,spos);
     235           0 :             sterm = term.substr(spos+1,string::npos);
     236             :         }
     237             : 
     238           0 :         if (sterm.empty()) return false;
     239             : 
     240           0 :         if (toptags) {
     241           0 :             assert(elem_chain==NULL);
     242           0 :             assert(tagmap==NULL);
     243           0 :             if (sterm[0] != '.') {
     244             :                 // These are top-level tags
     245             : 
     246             :                 // We do not allow prefixes with top-level tags            
     247           0 :                 if (!pterm.empty()) return false;
     248             : 
     249           0 :                 toptags->push_back(sterm);
     250             :             }
     251             :             
     252           0 :             continue;
     253             :         } else {
     254           0 :             assert(elem_chain);
     255           0 :             assert(elem_chain->size()>1);
     256           0 :             assert(tagmap);
     257           0 :             if (sterm[0] != '.') {
     258             :                 // We are not processing at the top level
     259             :                 // Ignore top-level tags 
     260           0 :                 continue;
     261             :             }
     262             :         }
     263             : 
     264           0 :         string sname, pname;
     265             : 
     266             :         // strip out the leading "."
     267           0 :         sname = sterm.substr(1, string::npos);
     268           0 :         size_t sz = elem_chain->size();
     269           0 :         StatWalker::TagVal tv;
     270             : 
     271           0 :         if (sname.compare(g_viz_constants.STAT_KEY_FIELD)==0) {
     272           0 :             tv.val = elem_chain->at(sz-1).get<1>().second;
     273             :         } else {
     274             :             // TODO: Add support for map value as tag
     275           0 :             const ElemVar& ev = elem_chain->at(sz-1).get<1>().first;
     276           0 :             pugi::xml_node anode_s;
     277             : 
     278           0 :             DomChildVisitor dcv; 
     279           0 :             boost::apply_visitor(dcv, ev);
     280           0 :             dcv.GetResult(sname, anode_s);
     281             : 
     282           0 :             if (!anode_s) return false;
     283           0 :             tv.val = ParseNode(anode_s);
     284             :         }
     285             : 
     286           0 :         if (!pterm.empty()) {
     287             :             // The prefix is a child of the deepest node,
     288             :             // or a child at the current level (2nd deepest node)
     289           0 :             size_t idx = ((pterm[0] == '.') ? sz-1 : sz-2);
     290           0 :             for (size_t ix=1; ix<=idx; ix++) {
     291           0 :                 if (!pname.empty()) pname.append(".");
     292           0 :                 pname.append(elem_chain->at(ix).get<0>());
     293             :             }
     294           0 :             if (pterm[0] != '.') {
     295           0 :                 if (!pname.empty()) pname.append(".");
     296             :             }
     297           0 :             pname.append(pterm);
     298           0 :             size_t found = pterm.rfind('.');
     299           0 :             string pattr = pterm.substr(found+1, string::npos);
     300           0 :             DbHandler::Var pv;
     301           0 :             if (pattr.compare(g_viz_constants.STAT_KEY_FIELD)==0) {
     302           0 :                 pv = elem_chain->at(idx).get<1>().second;
     303             :             } else {
     304             :                 // TODO: Add support for map value as tag
     305           0 :                 const ElemVar& ev = elem_chain->at(idx).get<1>().first;
     306           0 :                 pugi::xml_node anode_p;
     307             : 
     308           0 :                 DomChildVisitor dcv; 
     309           0 :                 boost::apply_visitor(dcv, ev);
     310           0 :                 dcv.GetResult(pattr, anode_p);
     311             : 
     312           0 :                 if (!anode_p) return false;
     313           0 :                 pv = ParseNode(anode_p);
     314             :             }
     315           0 :             tv.prefix = make_pair(pname, pv);
     316           0 :         }
     317             : 
     318           0 :         tagmap->insert(make_pair(sname, tv));
     319             : 
     320           0 :     } while (npos != string::npos);
     321             : 
     322           0 :     return true;
     323             : }
     324             : 
     325           0 : static bool DomValidElems(pugi::xml_node node,
     326             :         ptr_vector<ElemT> &elem_list, std::string& ltype) {
     327             :     
     328           0 :     if (strcmp(node.attribute("type").value(), "list") == 0) {
     329           0 :         pugi::xml_node subs = node.child("list");
     330           0 :         ltype = subs.attribute("type").value();
     331           0 :         for (pugi::xml_node elem = subs.first_child(); elem;
     332           0 :                 elem = elem.next_sibling()) {
     333           0 :             if (ltype == "struct") {
     334           0 :                 elem_list.push_back(new pair<ElemVar,string>(elem,string()));
     335             :             } else {
     336           0 :                 DbHandler::Var sample;
     337           0 :                 if (ParseNodeImpl(sample, ltype, elem)) {
     338           0 :                     elem_list.push_back(new pair<ElemVar,string>(sample, string()));
     339             :                 } else {
     340           0 :                     return false;
     341             :                 }
     342           0 :             }
     343             :         }
     344           0 :     } else if (strcmp(node.attribute("type").value(), "struct") == 0) {
     345           0 :         elem_list.push_back(new pair<ElemVar, string>(
     346           0 :                 node.first_child(),string()));
     347           0 :     } else if (strcmp(node.attribute("type").value(), "map") == 0) {
     348           0 :         pugi::xml_node subs = node.child("map");
     349           0 :         ltype = subs.attribute("value").value();
     350           0 :         string key("__UNKNOWN__");
     351           0 :         uint32_t idx = 0;
     352           0 :         for (pugi::xml_node elem = subs.first_child(); elem;
     353           0 :                 elem = elem.next_sibling()) {
     354           0 :             if (idx % 2) {
     355           0 :                 if (ltype == "struct") {
     356           0 :                     elem_list.push_back(new pair<ElemVar, string>(elem,key));
     357             :                 } else {
     358           0 :                     DbHandler::Var sample;
     359           0 :                     if (ParseNodeImpl(sample, ltype, elem)) {
     360           0 :                         elem_list.push_back(new pair<ElemVar, string>(
     361           0 :                                 sample, key));
     362             :                     } else {
     363           0 :                         return false;
     364             :                     }
     365           0 :                 }
     366           0 :                 key = string("__UNKNOWN__");
     367             :             } else {
     368           0 :                 std::string val(elem.child_value());
     369           0 :                 TXMLProtocol::unescapeXMLControlChars(val);
     370           0 :                 key = val;
     371           0 :             }
     372           0 :             idx++;
     373             :         }
     374           0 :     } else {
     375           0 :         return false;
     376             :     }
     377           0 :     return true;
     378             : }
     379             : 
     380             : class DomStatVisitor : public boost::static_visitor<> {
     381             :   public:
     382           0 :     void operator()(const pugi::xml_node& node) {
     383           0 :         for (pugi::xml_node sattr = node.first_child(); sattr;
     384           0 :                 sattr = sattr.next_sibling()) {
     385           0 :             DbHandler::Var sample = ParseNode(sattr, true);
     386           0 :             if (sample.type == DbHandler::INVALID) {
     387             :             //  for structs or lists, look for the tags annotation
     388             :             //  and process for stats.
     389             :             //  Ignore any struct or list that does not have the
     390             :             //  tags annotation
     391           0 :                 if (sattr.attribute("tags").empty()) {
     392           0 :                     LOG(DEBUG, __func__ << " Message: "  << 
     393             :                       " Name: " << node.name() <<  " Child: " <<
     394             :                       sattr.name()  << " No tags annotation ");
     395           0 :                     continue;
     396           0 :                 }
     397           0 :                 string ltype;
     398           0 :                 ptr_vector<ElemT> elem_list;
     399           0 :                 if (!DomValidElems(sattr, elem_list, ltype)) {
     400           0 :                     LOG(ERROR, __func__ << " Message: "  << 
     401             :                       " Name: " << node.name() <<  " Child: " << sattr.name()  <<
     402             :                       (ltype.empty() ? " Bad Stat type in walk" :
     403             :                                        " Bad Stat list type in walk") <<
     404             :                       (ltype.empty() ? node.attribute("type").value() : ltype));
     405           0 :                     continue;
     406           0 :                 }
     407           0 :                 elem_map[sattr.name()] = make_pair(sattr.attribute("tags").value(),
     408           0 :                                                    elem_list);
     409           0 :             } else { 
     410             :             // For simple attributes (strings, integers and doubles)
     411             :             // record the attributes in the stat tables
     412           0 :                 attribs.insert(make_pair(sattr.name(), sample));
     413             :             }
     414           0 :         }
     415           0 :     }
     416           0 :     void operator()(const DbHandler::Var& dv) {
     417           0 :         attribs.insert(make_pair(
     418             :                 g_viz_constants.STAT_VALUE_FIELD, dv));
     419           0 :     }
     420             : 
     421             :     DbHandler::AttribMap attribs;
     422             :     // For this map:
     423             :     //     the key is the attribute name
     424             :     //     the value is a pair of the tags string, and ElemT
     425             :     map<string, pair<string, ptr_vector<ElemT> > > elem_map;
     426             : 
     427           0 :     void GetResult(DbHandler::AttribMap& lattribs,
     428             :             map<string, pair<string, ptr_vector<ElemT> > >& lelem_map) {
     429           0 :         lattribs = attribs;
     430           0 :         lelem_map = elem_map;
     431           0 :     }
     432             : };
     433             : 
     434             : class DomSelfVisitor : public boost::static_visitor<> {
     435             :   public:
     436           0 :     void operator()(const pugi::xml_node& node) {
     437           0 :         se = node;
     438           0 :     }
     439           0 :     void operator()(const DbHandler::Var& dv) {
     440           0 :     }
     441             : 
     442             :     pugi::xml_node se;
     443             : 
     444           0 :     void GetResult(pugi::xml_node& node) {
     445           0 :         node = se;
     446           0 :     }
     447             : };
     448             : /* This function recursively walks the XML DOM
     449             :    for objectlog and UVE messages and processes
     450             :    them for stats.
     451             :    It is invoked after finding a top-level
     452             :    stats attribute
     453             : */
     454           0 : static bool DomStatWalker(StatWalker& sw,
     455             :         const std::string& tstr,
     456             :         ptr_vector<tuple<string,ElemT> > elem_chain) {
     457             : 
     458           0 :     pugi::xml_node object;
     459             :  
     460           0 :     DomSelfVisitor dsv; 
     461           0 :     boost::apply_visitor(dsv, elem_chain.at(0).get<1>().first);
     462           0 :     dsv.GetResult(object);
     463             :     
     464           0 :     size_t sz = elem_chain.size();
     465             : 
     466           0 :     const ElemVar& ev = elem_chain.at(sz-1).get<1>().first;
     467           0 :     const string& node_key = elem_chain.at(sz-1).get<1>().second;
     468           0 :     string node_name = elem_chain.at(sz-1).get<0>();
     469           0 :     StatWalker::TagMap tagmap;
     470             :     // Parse the tags annotation to find all tags that will
     471             :     // be used to index stats samples
     472           0 :     if (ParseDomTags(tstr, NULL, &elem_chain, &tagmap)) {
     473           0 :         DbHandler::AttribMap attribs;
     474             :         // For this map:
     475             :         //     the key is the attribute name
     476             :         //     the value is a pair of the tags string, and ElemT
     477           0 :         map<string, pair<string, ptr_vector<ElemT> > > elem_map;
     478             :         // Load all tags and non-tags
     479             :        
     480           0 :         DomStatVisitor dsv; 
     481           0 :         boost::apply_visitor(dsv, ev);
     482           0 :         dsv.GetResult(attribs, elem_map);
     483             : 
     484           0 :         if (!node_key.empty()) {
     485           0 :             attribs.insert(make_pair(g_viz_constants.STAT_KEY_FIELD,
     486             :                     node_key));
     487             :         }
     488           0 :         sw.Push(node_name, tagmap, attribs);
     489             : 
     490           0 :         for (map<string, pair<string, ptr_vector<ElemT> > >::iterator ei =
     491           0 :                 elem_map.begin(); ei != elem_map.end(); ei++) {
     492           0 :             ptr_vector<ElemT> & elem_list = ei->second.second;
     493           0 :             string & tstr_sub(ei->second.first);
     494           0 :             for (size_t idx=0; idx<elem_list.size(); idx++) {
     495           0 :                 ptr_vector<tuple<string,ElemT> > elem_parent = elem_chain;
     496           0 :                 elem_parent.push_back(new tuple<string,ElemT>(ei->first, elem_list[idx]));
     497             :                 // recursive invokation to process stats of child
     498             :                 // structs and lists that have the tags annotation
     499           0 :                 if (!DomStatWalker(sw, tstr_sub, elem_parent)) {
     500           0 :                     LOG(ERROR, __func__ << 
     501             :                       " Name: " << object.name() <<  " Node: " << node_name  <<
     502             :                       " Bad element " << ei->first);
     503             :                 }
     504           0 :             }
     505             :         }
     506           0 :         sw.Pop();
     507           0 :     } else {
     508           0 :         LOG(ERROR, __func__ <<
     509             :           " Name: " << object.name() <<  " Node: " << node_name  <<
     510             :           " Bad tags " << tstr); 
     511           0 :         return false;
     512             :     }
     513           0 :     return true;
     514           0 : }
     515             : 
     516             : /* 
     517             :     This function is used to analyse an objectlog or UVE for stats attributes
     518             :     and walk the XML DOM to process the stats
     519             : */
     520             : 
     521           0 : static bool DomTopStatWalker(const pugi::xml_node& object,
     522             :         DbHandler *db,
     523             :         uint64_t timestamp,
     524             :         const pugi::xml_node& node,
     525             :         StatWalker::TagMap tmap,
     526             :         const std::string& source,
     527             :         GenDb::GenDbIf::DbAddColumnCb db_cb) {
     528             : 
     529           0 :     ptr_vector<ElemT> elem_list;
     530           0 :     string ltype;
     531             :     // We accept both structs and lists of structs for stats
     532             :     // For structs, we need to process a singe element.
     533             :     // Otherwise we process each element of the list
     534           0 :     if (!DomValidElems(node, elem_list, ltype)) {
     535           0 :         LOG(ERROR, __func__ << " Source: " << source << 
     536             :           " Name: " << object.name() <<  " Node: " << node.name()  <<
     537             :           (ltype.empty() ? " Bad Stat type " : " Bad Stat list type") <<
     538             :           (ltype.empty() ? node.attribute("type").value() : ltype));
     539           0 :         return false;
     540             :     }
     541             : 
     542           0 :     std::vector<std::string> toptags;
     543             : 
     544           0 :     string tstr(node.attribute("tags").value());
     545             : 
     546             :     // Get the top-level tags for this stat attribute
     547           0 :     if (ParseDomTags(tstr, &toptags, NULL, NULL)) {
     548             : 
     549           0 :         StatWalker::TagMap m1 = tmap;
     550             : 
     551           0 :         for (size_t idx=0; idx < toptags.size(); idx++) {
     552             :             pugi::xml_node anode_p =
     553           0 :                 object.child(toptags.at(idx).c_str());
     554           0 :             StatWalker::TagVal th;
     555           0 :             th.val = ParseNode(anode_p);
     556           0 :             m1.insert(make_pair(toptags.at(idx), th));
     557           0 :         } 
     558             :         
     559           0 :         StatWalker sw(boost::bind(&DbHandler::StatTableInsert, db,
     560           0 :             _1, _2, _3, _4, _5, db_cb), timestamp, object.name(), m1);
     561             : 
     562           0 :         ptr_vector<tuple<string, ElemT> > parent_chain;
     563           0 :         parent_chain.push_back(new tuple<string, ElemT>(object.name(),
     564           0 :                 make_pair<ElemVar, string>(object,string())));
     565             : 
     566             :         // Process all elements the next level down for stats
     567           0 :         for (size_t idx=0; idx<elem_list.size(); idx++) {
     568           0 :             ptr_vector<tuple<string, ElemT> > elem_chain = parent_chain; 
     569           0 :             elem_chain.push_back(new tuple<string, ElemT>(node.name(), elem_list[idx]));
     570           0 :             if (!DomStatWalker(sw, tstr, elem_chain)) {
     571           0 :                 LOG(ERROR, __func__ << " Source: " << source <<
     572             :                   " Name: " << object.name() <<  " Node: " << node.name());
     573           0 :                 continue;
     574           0 :             }
     575           0 :         }
     576           0 :     } else {
     577           0 :         LOG(ERROR, __func__ << " Source: " << source <<
     578             :           " Name: " << object.name() <<  " Node: " << node.name()  <<
     579             :           " Bad tags " << tstr); 
     580           0 :         return false;
     581             :     }
     582           0 :     return true;
     583           0 : }
     584             : 
     585             : /*
     586             :  * Walk the XML DOM to find keys to record this message against.
     587             :  * Write to the objectlog accordingly
     588             :  */
     589           0 : static size_t DomObjectWalk(const pugi::xml_node& parent, const VizMsg *rmsg,
     590             :         DbHandler *db, uint64_t timestamp,
     591             :         DbHandler::ObjectNamesVec *object_names,
     592             :         GenDb::GenDbIf::DbAddColumnCb db_cb) {
     593           0 :     std::map<std::string, std::string> keymap;
     594           0 :     std::map<std::string, std::string>::iterator it;
     595             :     const char *table;
     596             :     const char *nodetype;
     597           0 :     std::string rowkey;
     598             : 
     599           0 :     for (pugi::xml_node node = parent.first_child(); node;
     600           0 :          node = node.next_sibling()) {
     601           0 :         table = node.attribute("key").value();
     602           0 :         nodetype = node.attribute("type").value();
     603           0 :         if (strcmp(table, "") && strcmp(nodetype, "")) {
     604             :             // check if Sandesh node has a map attribute;
     605             :             // key type of map should not be extracted,
     606             :             // only key value of attribute should be extracted
     607           0 :             rowkey = std::string(node.child_value());
     608           0 :             TXMLProtocol::unescapeXMLControlChars(rowkey);
     609           0 :             it = keymap.find(table);
     610           0 :             if (it != keymap.end()) {
     611           0 :                 std::string tempstr(it->second);
     612           0 :                 tempstr.append(":");
     613           0 :                 tempstr.append(rowkey);
     614           0 :                 keymap.erase(it);
     615           0 :                 keymap.insert(std::pair<std::string, std::string>(table, tempstr));
     616           0 :             } else {
     617           0 :                 keymap.insert(std::pair<std::string, std::string>(table, rowkey));
     618             :             }
     619             :         }
     620             :     }
     621           0 :     for (it = keymap.begin(); it != keymap.end(); it++) {
     622           0 :         db->ObjectTableInsert(it->first, it->second, 
     623           0 :             timestamp, rmsg->unm, rmsg, db_cb);
     624           0 :         std::string tempstr(it->first);
     625           0 :         tempstr.append(":");
     626           0 :         tempstr.append(it->second);
     627           0 :         object_names->push_back(tempstr);
     628           0 :     }
     629           0 :     for (pugi::xml_node node = parent.first_child(); node;
     630           0 :          node = node.next_sibling()) {
     631           0 :         DomObjectWalk(node, rmsg, db, timestamp, object_names, db_cb);
     632             :     }
     633           0 :     return keymap.size();
     634           0 : }
     635             : 
     636             : /*
     637             :  * Check if any handling is needed for the message wrt to ObjectLog
     638             :  * Looks for the 'key' annotations for the table name and inserts
     639             :  * the object trace with the rowkey corresponding to the value of the
     640             :  * field
     641             :  */
     642           0 : void Ruleeng::handle_object_log(const pugi::xml_node& parent, const VizMsg *rmsg,
     643             :         DbHandler *db, const SandeshHeader &header,
     644             :         DbHandler::ObjectNamesVec *object_names,
     645             :         GenDb::GenDbIf::DbAddColumnCb db_cb) {
     646           0 :     if (!(header.get_Hints() & g_sandesh_constants.SANDESH_KEY_HINT)) {
     647           0 :         return;
     648             :     }
     649           0 :     uint64_t timestamp(header.get_Timestamp());
     650           0 :     std::string source(header.get_Source());
     651           0 :     std::string type(rmsg->msg->GetMessageType());
     652           0 :     std::string module(header.get_Module());
     653           0 :     std::string instance_id(header.get_InstanceId());
     654           0 :     std::string node_type(header.get_NodeType());
     655           0 :     SandeshType::type sandesh_type(header.get_Type());
     656             : 
     657           0 :     DomObjectWalk(parent, rmsg, db, timestamp, object_names, db_cb);
     658             : 
     659             :     // UVE related stats are not processed here. See handle_uve_publish.
     660           0 :     if (sandesh_type == SandeshType::UVE) {
     661           0 :         return;
     662             :     }
     663             : 
     664             :     // All stats records the "name" field as a tag.
     665             :     // If no such field is present, use the source of
     666             :     // this message  
     667           0 :     DbHandler::Var nkey = source;
     668             : 
     669           0 :     StatWalker::TagMap m1;
     670           0 :     StatWalker::TagVal h1,h2; 
     671           0 :     h2.val = source;
     672           0 :     m1.insert(make_pair(g_viz_constants.STAT_SOURCE_FIELD, h2));
     673             : 
     674           0 :     pugi::xml_node object(parent);
     675           0 :     for (pugi::xml_node node = object.first_child(); node;
     676           0 :            node = node.next_sibling()) {
     677           0 :         if (!strcmp(node.name(), g_viz_constants.STAT_OBJECTID_FIELD.c_str())) {
     678           0 :             nkey = ParseNode(node);
     679             :         }
     680             :     }
     681           0 :     h1.val = nkey;
     682           0 :     m1.insert(make_pair(g_viz_constants.STAT_OBJECTID_FIELD, h1));
     683             :     
     684           0 :     for (pugi::xml_node node = object.first_child(); node;
     685           0 :            node = node.next_sibling()) {
     686             : 
     687           0 :         if (!node.attribute("tags").empty()) {
     688           0 :            DomTopStatWalker(object, db, timestamp, node,
     689             :                    m1, source, db_cb);
     690             :         }
     691             :     }
     692           0 : }
     693             : 
     694           0 : bool Ruleeng::handle_uve_statistics(const pugi::xml_node& parent,
     695             :     const VizMsg *rmsg, DbHandler *db, const SandeshHeader& header,
     696             :     GenDb::GenDbIf::DbAddColumnCb db_cb) {
     697           0 :     const SandeshType::type& sandesh_type(header.get_Type());
     698           0 :     if ((sandesh_type != SandeshType::UVE) &&
     699           0 :         (sandesh_type != SandeshType::ALARM)) {
     700           0 :         return true;
     701             :     }
     702             : 
     703           0 :     std::string type(rmsg->msg->GetMessageType());
     704           0 :     std::string source(header.get_Source());
     705           0 :     std::string module(header.get_Module());
     706           0 :     std::string instance_id(header.get_InstanceId());
     707           0 :     std::string node_type(header.get_NodeType());
     708           0 :     int64_t ts(header.get_Timestamp());
     709             : 
     710           0 :     pugi::xml_node object(parent);
     711           0 :     if (!object) {
     712           0 :         LOG(ERROR, __func__ << " Message: " << type << " : " << source <<
     713             :             ":" << node_type << ":" << module << ":" << instance_id <<
     714             :             " object NOT PRESENT: " << rmsg->msg->ExtractMessage());
     715           0 :         return false;
     716             :     }
     717             : 
     718           0 :     object = object.child("data");
     719           0 :     object = object.first_child();
     720             : 
     721           0 :     for (pugi::xml_node node = object.first_child(); node;
     722           0 :            node = node.next_sibling()) {
     723           0 :         if (strcmp(node.attribute("key").value(), "")) {
     724           0 :             continue;
     725             :         }
     726             :         // Ignore deleted
     727           0 :         if (!strcmp(node.name(), "deleted")) {
     728           0 :             if (!strcmp(node.child_value(), "true")) {
     729           0 :                 return true;
     730             :             }
     731             :         }
     732           0 :         if (!node.attribute("tags").empty()) {
     733             :             // For messages send during UVE Sync, stats must be ignored
     734           0 :             if (header.get_Hints() & g_sandesh_constants.SANDESH_SYNC_HINT) {
     735           0 :                 continue;
     736             :             }
     737             :             pugi::xml_node anode_p =
     738           0 :                 object.child(g_viz_constants.STAT_OBJECTID_FIELD.c_str());
     739           0 :             StatWalker::TagMap m1;
     740           0 :             StatWalker::TagVal h1,h2;
     741           0 :             h1.val = ParseNode(anode_p);
     742           0 :             m1.insert(make_pair(g_viz_constants.STAT_OBJECTID_FIELD, h1));
     743           0 :             h2.val = source;
     744           0 :             m1.insert(make_pair(g_viz_constants.STAT_SOURCE_FIELD, h2));
     745             :             // Process this UVE's Stat attributes.
     746             :             // We will always index by Source and UVE key (name)
     747             :             // Other indexes depend on the "tags" attribute
     748           0 :             if (!DomTopStatWalker(object, db, ts, node,
     749             :                     m1, source, db_cb)) {
     750           0 :                 continue;
     751             :             }
     752           0 :         }
     753             :     }
     754           0 :     return true;
     755           0 : }
     756             : 
     757           0 : bool Ruleeng::handle_uve_publish(const pugi::xml_node& parent,
     758             :     const VizMsg *rmsg, DbHandler *db, const SandeshHeader& header,
     759             :     GenDb::GenDbIf::DbAddColumnCb db_cb) {
     760           0 :     const SandeshType::type& sandesh_type(header.get_Type());
     761           0 :     if ((sandesh_type != SandeshType::UVE) &&
     762           0 :         (sandesh_type != SandeshType::ALARM)) {
     763           0 :         return true;
     764             :     }
     765             : 
     766           0 :     bool is_alarm = (sandesh_type == SandeshType::ALARM) ? true : false;
     767             : 
     768           0 :     std::string type(rmsg->msg->GetMessageType());
     769           0 :     std::string source(header.get_Source());
     770           0 :     std::string module(header.get_Module());
     771           0 :     std::string instance_id(header.get_InstanceId());
     772           0 :     std::string node_type(header.get_NodeType());
     773           0 :     int32_t seq(header.get_SequenceNum());
     774           0 :     int64_t ts(header.get_Timestamp());
     775             : 
     776           0 :     pugi::xml_node object(parent);
     777           0 :     if (!object) {
     778           0 :         LOG(ERROR, __func__ << " Message: " << type << " : " << source <<
     779             :             ":" << node_type << ":" << module << ":" << instance_id <<
     780             :             " object NOT PRESENT: " << rmsg->msg->ExtractMessage());
     781           0 :         return false;
     782             :     }
     783             : 
     784           0 :     object = object.child("data");
     785           0 :     object = object.first_child();
     786             : 
     787           0 :     std::string barekey;
     788             :     const char *tempstr;
     789           0 :     std::string rowkey;
     790           0 :     std::string table;
     791           0 :     std::string object_name(object.name());
     792             : 
     793           0 :     bool deleted = false;
     794           0 :     for (pugi::xml_node node = object.first_child(); node;
     795           0 :             node = node.next_sibling()) {
     796             :         
     797           0 :         tempstr = node.attribute("key").value();
     798           0 :         if (strcmp(tempstr, "")) {
     799           0 :             rowkey = std::string(node.child_value());
     800           0 :             TXMLProtocol::unescapeXMLControlChars(rowkey);
     801           0 :             if (!barekey.empty()) {
     802           0 :                 barekey.append(":");
     803           0 :                 barekey.append(rowkey);
     804             :             } else {
     805           0 :                 table = std::string(tempstr);
     806           0 :                 barekey.append(rowkey);
     807             :             }
     808             :         }
     809           0 :         if (!strcmp(node.name(), "deleted")) {
     810           0 :             if (!strcmp(node.child_value(), "true")) {
     811           0 :                 deleted = true;
     812             :             }
     813             :         }
     814           0 :         if (!strcmp(node.name(), "proxy")) {
     815           0 :             object_name = object_name +
     816           0 :                     string("-") + node.child_value();
     817             :         }
     818             :     }
     819             : 
     820           0 :     std::string key = table + ":" + barekey;
     821             : 
     822           0 :     if (table.empty()) {
     823           0 :         LOG(ERROR, __func__ << " Message: " << type << " : " << source <<
     824             :             ":" << node_type << ":" << module << ":" << instance_id <<
     825             :             " key NOT PRESENT");
     826           0 :         return false;
     827             :     }
     828             : 
     829           0 :     map<string,pair<string,pugi::xml_node> > vmap;
     830           0 :     if (deleted) {
     831           0 :         if (!osp_->UVEDelete(object_name, source, node_type, module, 
     832             :                              instance_id, key, seq, is_alarm)) {
     833           0 :             LOG(ERROR, __func__ << " Cannot Delete " << key);
     834           0 :             PUBLISH_UVE_DELETE_TRACE(UVETraceBuf, source, module, object_name, key,
     835             :                 seq, false, node_type, instance_id);
     836             :         } else {
     837           0 :             PUBLISH_UVE_DELETE_TRACE(UVETraceBuf, source, module, object_name, key,
     838             :                 seq, true, node_type, instance_id);
     839             :         }
     840           0 :         LOG(DEBUG, __func__ << " Deleted " << key);
     841           0 :         osp_->UVENotif(object_name,
     842             :             source, node_type, module, instance_id, table, barekey, vmap ,deleted);
     843           0 :         return true;
     844             :     }
     845             : 
     846           0 :     for (pugi::xml_node node = object.first_child(); node;
     847           0 :            node = node.next_sibling()) {
     848           0 :         std::ostringstream ostr; 
     849           0 :         std::ostringstream tstr;
     850           0 :         node.print(ostr, "", pugi::format_raw | pugi::format_no_escapes);
     851           0 :         std::string agg;
     852           0 :         std::string atyp;
     853           0 :         tempstr = node.attribute("key").value();
     854           0 :         if (strcmp(tempstr, "")) {
     855           0 :             continue;
     856             :         }
     857             :         // "node" has the underlying XML node.
     858             :         // "ostr" is the encoded attribute for the UVE
     859           0 :         vmap.insert(make_pair(node.name(), make_pair(ostr.str(), node)));
     860           0 :         tempstr = node.attribute("aggtype").value();
     861           0 :         if (strcmp(tempstr, "")) {
     862           0 :             agg = std::string(tempstr);
     863             :         } else {
     864           0 :             agg = std::string("None");
     865             :         }
     866             : 
     867           0 :         if (!osp_->UVEUpdate(object_name, node.name(),
     868             :                              source, node_type, module, instance_id,
     869           0 :                              table, barekey, ostr.str(), seq,
     870             :                              agg, ts,
     871             :                              is_alarm)) {
     872           0 :             LOG(ERROR, __func__ << " Message: "  << type << " : " << source <<
     873             :               ":" << node_type << ":" << module << ":" << instance_id <<
     874             :               " Name: " << object.name() <<  " UVEUpdate Failed"); 
     875           0 :             PUBLISH_UVE_UPDATE_TRACE(UVETraceBuf, source, module, object_name, key, 
     876             :                 node.name(), false, node_type, instance_id);
     877             :         } else {
     878           0 :             PUBLISH_UVE_UPDATE_TRACE(UVETraceBuf, source, module, object_name, key,
     879             :                 node.name(), true, node_type, instance_id);
     880             :         }
     881           0 :     }
     882             : 
     883             :     // Publish on the Kafka bus that this UVE has changed
     884           0 :     osp_->UVENotif(object_name, 
     885             :         source, node_type, module, instance_id, table, barekey, vmap, deleted);
     886           0 :     return true;
     887           0 : }
     888             : 
     889           0 : bool Ruleeng::handle_session_object(const pugi::xml_node &parent,
     890             :     DbHandler *db, const SandeshHeader &header,
     891             :     GenDb::GenDbIf::DbAddColumnCb db_cb) {
     892           0 :     if (header.get_Type() != SandeshType::SESSION) {
     893           0 :         return true;
     894             :     }
     895           0 :     if(!(db->SessionTableInsert(parent, header, db_cb))) {
     896           0 :         return false;
     897             :     }
     898           0 :     return true;
     899             : }
     900             : 
     901           0 : bool Ruleeng::rule_execute(const VizMsg *vmsgp, bool uveproc, DbHandler *db,
     902             :     GenDb::GenDbIf::DbAddColumnCb db_cb) {
     903           0 :     DbHandler::ObjectNamesVec object_names;
     904           0 :     const SandeshXMLMessage *sxmsg =
     905             :         static_cast<const SandeshXMLMessage *>(vmsgp->msg);
     906           0 :     const SandeshHeader &header(sxmsg->GetHeader());
     907           0 :     const pugi::xml_node &parent(sxmsg->GetMessageNode());
     908           0 :     remove_identifier(parent);
     909             :     // First publish to redis and kafka
     910           0 :     if (uveproc) handle_uve_publish(parent, vmsgp, db, header, db_cb);
     911             :     // Check if the message needs to be dropped
     912           0 :     if (db && db->DropMessage(header, vmsgp)) {
     913           0 :         return true;
     914             :     }
     915             : 
     916           0 :     if (db) {
     917             :         // 1. make entry in OBJECT_VALUE_TABLE if needed
     918             :         // 2. get object-type:name{1-6}
     919           0 :         handle_object_log(parent, vmsgp, db, header, &object_names, db_cb);
     920             : 
     921             :         // Insert into the message table
     922           0 :         db->MessageTableInsert(vmsgp, object_names, db_cb);
     923             : 
     924           0 :         if (uveproc) handle_uve_statistics(parent, vmsgp, db, header, db_cb);
     925             : 
     926           0 :         handle_session_object(parent, db, header, db_cb);
     927             :     }
     928             : 
     929           0 :     RuleMsg rmsg(vmsgp); 
     930           0 :     rulelist_->rule_execute(rmsg);
     931           0 :     return true;
     932           0 : }

Generated by: LCOV version 1.14