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

Generated by: LCOV version 1.14