3b74acdaa89d45c431c1fc743c89a3330c8fa942
[com/gs-lite.git] / src / ftacmp / iface_q.cc
1 /* ------------------------------------------------
2 Copyright 2014 AT&T Intellectual Property
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at
6
7      http://www.apache.org/licenses/LICENSE-2.0
8
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License.
14  ------------------------------------------- */
15 #include "iface_q.h"
16 #include<errno.h>
17 #include <unistd.h>
18 #include <algorithm>
19 #include <cctype>
20
21
22 using namespace std;
23
24 extern string hostname;         // namne of the current host
25
26 static string int_to_string(int i){
27     string ret;
28     char tmpstr[100];
29     sprintf(tmpstr,"%d",i);
30     ret=tmpstr;
31     return(ret);
32 }
33
34
35 //              Interface for the res parser
36 extern int ResParserparse(void);
37 extern FILE *ResParserin;
38 extern int ResParserdebug;
39 void ResParser_setfileinput(FILE *f);
40 void ResParser_setstringinput(char *s);
41 extern int flex_res_lineno;
42
43 resparse_data *rpd_ptr;
44 vector<string> res_val_vec, res_attr_vec;
45 string res_a, res_v;
46
47 ///////////////////////////////////////
48 ///             iface_t methods
49
50         void iface_t::add_property(const char *name, const char *att){
51                 string nm(name);
52                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);
53                 vals[nm].push_back(att);
54         }
55
56         void iface_t::add_property(const char *name, const char **atts){
57                 string val = "";
58                 string nm = name;
59                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);
60                 if(atts[0]) val = atts[1];
61
62                 vals[nm].push_back(val);
63         }
64
65         void iface_t::add_property(const char *name, vector<string> &val_vec){
66                 string val = "";
67                 string nm = name;
68                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);
69                 if(val_vec.size()) val = val_vec[0];
70
71                 vals[nm].push_back(val);
72         }
73
74         int iface_t::finalize(string &errs){
75                 string tag ="ERROR in interface starting at line "+int_to_string(lineno)+", ";
76                 string e;
77                 if(vals.count("name") == 0){
78                         e += "Name not specified. ";
79                 }else{
80                         if(vals["name"].size() > 1){
81                                 e+="More than one name specified. ";
82                         }
83                 }
84
85                 if(e != ""){
86                         errs += tag + e + "\n";
87                         return(1);
88                 }
89                 return(0);
90         }
91
92         string iface_t::to_string(){
93                 int i;
94                 string ret = "Interface "+vals["name"][0]+":\n";
95                 map<string, vector<string> >::iterator svmi;
96                 for(svmi=vals.begin();svmi!=vals.end();++svmi){
97                         ret += "\t"+(*svmi).first + " : ";
98                         for(i=0;i<((*svmi).second).size();++i){
99                                 if(i>0) ret+=", ";
100                                 ret += (*svmi).second[i];
101                         }
102                         ret += "\n";
103                 }
104
105                 return ret;
106         }
107
108         string iface_t::get_name(){
109                 if(vals.count("name") == 0) return (string)"";
110                 return (vals["name"])[0];
111         }
112
113         string iface_t::get_host(){
114                 if(vals.count("host") == 0) return (string)"";
115                 return (vals["host"])[0];
116         }
117
118
119         bool iface_t::eval_Contains(string prop, string val){
120                 // convert to lowercase
121                 std::transform(prop.begin(), prop.end(), prop.begin(), (int(*)(int))std::tolower);
122
123                 if(vals.count(prop) == 0) return false;
124                 int i;
125                 for(i=0;i<vals[prop].size();++i){
126                         if((vals[prop])[i] == val) return true;
127                 }
128                 return false;
129         }
130
131         bool iface_t::eval_Equals(string prop, string val){
132                 // convert to lowercase
133                 std::transform(prop.begin(), prop.end(), prop.begin(), (int(*)(int))std::tolower);
134                 if(vals.count(prop) == 0) return false;
135                 if(vals[prop].size() != 1) return false;
136                 int i;
137                 for(i=0;i<vals[prop].size();++i){
138                         if((vals[prop])[i] == val) return true;
139                 }
140                 return false;
141         }
142
143         bool iface_t::eval_Exists(string prop){
144                 // convert to lowercase
145                 std::transform(prop.begin(), prop.end(), prop.begin(), (int(*)(int))std::tolower);
146                 if(vals.count(prop) == 0) return false;
147                 return true;
148         }
149
150
151 ///////////////////////////////////////
152 ///             gs_host_t methods
153
154         void gs_host_t::add_property(const char *name, const char *att){
155                 string nm(name);
156                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);
157                 vals[nm].push_back(att);
158         }
159
160         void gs_host_t::add_property(const char *name, vector<string> &val_vec){
161                 string val = "";
162                 string nm = name;
163                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);
164                 if(val_vec.size()) val = val_vec[0];
165
166                 vals[nm].push_back(val);
167         }
168
169         int gs_host_t::finalize(string &errs){
170                 string tag ="ERROR in host starting at line "+int_to_string(lineno)+", ";
171                 string e;
172                 if(vals.count("name") == 0){
173                         e += "Name not specified. ";
174                 }else{
175                         if(vals["name"].size() > 1){
176                                 e+="More than one name specified. ";
177                         }
178                 }
179
180                 if(e != ""){
181                         errs += tag + e + "\n";
182                         return(1);
183                 }
184                 return(0);
185         }
186
187
188 /////////////////////////////////////////////////////////////////
189 ///             reparse_data methods
190
191         int resparse_data::finalize_iface(string &errs){
192                 int ret = curr_iface->finalize(errs);
193                 if(ret) {
194                         delete curr_iface;
195                         failure = true;
196                 }else{
197                         curr_host->add_interface(curr_iface);
198                 }
199                 return ret;
200         }
201
202
203         int resparse_data::finalize_host(string &errs){
204                 int ret = curr_host->finalize(errs);
205                 if(ret) {
206                         delete curr_host;
207                         failure = true;
208                 }else{
209
210                         string host = curr_host->vals["name"][0];
211                         // in non-distributed case we will ignore all other hosts
212                         if (!distributed_mode) {
213                                 char buf[1000];
214                                 if (host != hostname)
215                                         return ret;
216                         }
217                         // we need to exclude failed hosts
218                         if (!use_live_hosts_file || live_hosts->count(hostname)) {
219                                 hosts.push_back(curr_host);
220
221                                 // push the host name to every interface
222                                 curr_host->propagate_name();
223
224                                 // add all interfaces into interface list
225                                 for(int i=0;i<curr_host->ifaces.size();i++)
226                                         ifaces.push_back(curr_host->ifaces[i]);
227                         }
228                 }
229                 return ret;
230         }
231
232         string resparse_data::to_string(){
233                 string ret;
234                 int i;
235                 for(i=0;i<ifaces.size();i++)
236                         ret += ifaces[i]->to_string();
237                 return ret;
238         }
239
240         vector<pair<string,string> > resparse_data::find_ifaces(predicate_t *pr){
241                 int i;
242                 vector<pair<string,string> > ret;
243                 for(i=0;i<ifaces.size();++i){
244                         if(this->eval_pred(i,pr)){
245                                 pair<string,string> p(ifaces[i]->get_host(), ifaces[i]->get_name());
246                                 ret.push_back(p);
247                         }
248                 }
249                 return ret;
250         }
251
252
253         vector<int> resparse_data::get_ifaces_by_Name(std::string host_name, std::string if_name){
254                 int i;
255                 vector<int> ret;
256                 for(i=0;i<ifaces.size();++i){
257                         if(ifaces[i]->get_host() == host_name && ifaces[i]->get_name() == if_name)
258                                 ret.push_back(i);
259
260                 }
261                 return ret;
262         }
263
264
265         bool resparse_data::eval_pred(int i, predicate_t *pr){
266     vector<scalarexp_t *> op_list;
267         string prop, val;
268
269         switch(pr->get_operator_type()){
270         case PRED_IN:
271                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, IN not supported. %d\n",
272                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
273                 exit(1);
274         case PRED_COMPARE:
275                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, IN not supported. %d\n",
276                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
277                 exit(1);
278         case PRED_UNARY_OP:
279                 if(pr->get_op() == "NOT")
280                         return(! eval_pred(i, pr->get_left_pr()) );
281                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, unknown unary pred operator %s.\n",
282                         pr->get_lineno(), pr->get_charno(), pr->get_op().c_str() );
283                 exit(1);
284         case PRED_BINARY_OP:
285                 if(pr->get_op() == "AND"){
286                         if(! eval_pred(i, pr->get_left_pr()) ) return false;
287                         return  eval_pred(i, pr->get_right_pr()) ;
288                 }
289                 if(pr->get_op() == "OR"){
290                         if( eval_pred(i, pr->get_left_pr()) ) return true;
291                         return  eval_pred(i, pr->get_right_pr()) ;
292                 }
293                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, unknown binary pred operator %s.\n",
294                         pr->get_lineno(), pr->get_charno(), pr->get_op().c_str() );
295                 exit(1);
296         case PRED_FUNC:
297                 op_list = pr->get_op_list();
298                 if(op_list[0]->get_operator_type() != SE_PARAM){
299                         fprintf(stderr,"INTERNAL ERROR : ifq parameters are supposed to be of type SE_PARAM, found %s at position 0\n",op_list[0]->get_op().c_str());
300                         exit(1);
301                 }else{
302                         prop=op_list[0]->get_op();
303                 }
304                 if(op_list.size() > 1){
305                         if(op_list[1]->get_operator_type() != SE_PARAM){
306                                 fprintf(stderr,"INTERNAL ERROR : ifq parameters are supposed to be of type SE_PARAM, found %s at position 1\n",op_list[0]->get_op().c_str());
307                                 exit(1);
308                         }else{
309                                 val=op_list[1]->get_op();
310                         }
311                 }
312
313                 if(pr->get_op() == "Contains"){
314                         if(op_list.size() != 2){
315                                 fprintf(stderr,"INTERNAL ERROR : predicate Contains expects 2 parameters, received %lu\n",op_list.size());
316                                 exit(1);
317                         }
318                         return ifaces[i]->eval_Contains(prop,val);
319                 }
320
321                 if(pr->get_op() == "Equals"){
322                         if(op_list.size() != 2){
323                                 fprintf(stderr,"INTERNAL ERROR : predicate Equals expects 2 parameters, received %lu\n",op_list.size());
324                                 exit(1);
325                         }
326                         return ifaces[i]->eval_Equals(prop,val);
327                 }
328
329                 if(pr->get_op() == "Exists"){
330                         if(op_list.size() != 1){
331                                 fprintf(stderr,"INTERNAL ERROR : predicate Exists expects 1 parameter, received %lu\n",op_list.size());
332                                 exit(1);
333                         }
334                         return ifaces[i]->eval_Exists(prop);
335                 }
336
337                 fprintf(stderr,"INTERNAL ERROR : Unknown predicate %s in reparse_date::eval_pred.\n",pr->get_op().c_str());
338                 exit(1);
339
340         default:
341                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, unknown predicate operator type %d\n",
342                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );
343                 exit(1);
344         }
345
346         return(false);
347
348         }
349
350
351 ///////////////////////////////////////////
352 ///             XML parser callbacks for parsing interface resources
353
354 void startElement(void *userData, const char *name, const char **atts) {
355   int i;
356
357   resparse_data *rpd = (resparse_data *)userData;
358   rpd->level.push_back(name);
359
360   if(rpd->level.size() == 1 && rpd->level[0] == "Resources")
361         rpd->in_Resources = true;
362
363   if(rpd->in_Resources && rpd->level.size() == 2 && rpd->level[1] == "Interface"){
364 //      rpd->new_iface(XML_GetCurrentLineNumber(rpd->parser));
365         rpd->new_iface(1);
366     rpd->in_Iface = true;
367   }
368
369   if(rpd->in_Iface && rpd->level.size() == 3){
370         rpd->add_property(name, atts);
371   }
372
373
374 //  for(i=0;i<rpd->level.size();++i) printf("%s, ",rpd->level[i].c_str());
375 //  printf("\n");
376 }
377
378 void startElement(void *userData, const char *name, vector<string> &attr_vec, vector<string> &val_vec){
379   int i;
380
381   resparse_data *rpd = (resparse_data *)userData;
382   rpd->level.push_back(name);
383
384   if(rpd->level.size() == 1 && rpd->level[0] == "Resources")
385         rpd->in_Resources = true;
386
387   if(rpd->in_Resources && rpd->level.size() == 2 && rpd->level[1] == "Host"){
388 //      rpd->new_iface(XML_GetCurrentLineNumber(rpd->parser));
389
390         rpd->new_host(flex_res_lineno);
391         for (int i = 0; i < attr_vec.size(); ++i)
392                 rpd->curr_host->add_property(attr_vec[i].c_str(), val_vec[i].c_str());
393     rpd->in_Host = true;
394   }
395
396   if(rpd->in_Host && rpd->level.size() == 3) {
397           if ( rpd->level[2] == "Interface"){
398                 //      rpd->new_iface(XML_GetCurrentLineNumber(rpd->parser));
399                 rpd->new_iface(flex_res_lineno);
400                 for (int i = 0; i < attr_vec.size(); ++i)
401                         rpd->add_property(attr_vec[i].c_str(), val_vec[i].c_str());
402                 rpd->in_Iface = true;
403           } else {
404                 rpd->curr_host->add_property(name, val_vec);
405           }
406         }
407
408   if(rpd->in_Iface && rpd->level.size() == 4){
409         rpd->add_property(name, val_vec);
410   }
411
412
413 //  for(i=0;i<rpd->level.size();++i) printf("%s, ",rpd->level[i].c_str());
414 //  printf("\n");
415 }
416
417
418 void endElement(void *userData, const char *name) {
419   resparse_data *rpd = (resparse_data *)userData;
420
421   if(rpd->in_Iface && rpd->level.size() == 3){
422         string err_msg;
423         int err = rpd->finalize_iface(err_msg);
424         if(err) fprintf(stderr,"%s\n",err_msg.c_str());
425   } else if (rpd->in_Host && rpd->level.size() == 2) {
426         string err_msg;
427         int err = rpd->finalize_host(err_msg);
428         if(err) fprintf(stderr,"%s\n",err_msg.c_str());
429   }
430
431   rpd->level.pop_back();
432 }
433
434
435 //              Interface to ifq definition lexer and parser ...
436
437 extern int IfqParserparse(void);
438 extern FILE *IfqParserin;
439 extern int IfqParserdebug;
440 void IfqParser_setfileinput(FILE *f);
441 void IfqParser_setstringinput(char *s);
442
443
444 fta_parse_t *ifq_parse_result;
445
446 int ifq_t::load_ifaces(string fname, bool use_live_hosts_file, bool disributed_mode, string &err){
447   char buf[1000], errbuf[1000];
448 //  XML_Parser parser = XML_ParserCreate(NULL);
449
450   int done;
451   int depth = 0;
452   err="";
453
454   // open the list of failed hosts
455   set<string> live_hosts;
456   if (use_live_hosts_file) {
457           FILE* live_hosts_file = fopen("live_hosts.txt", "r");
458           if (!live_hosts_file) {
459                 err="Error, can't open live_hosts.txt, error is ";
460                 err+=strerror(errno); err+="\n";
461                 return(1);
462           }
463
464           while(fgets(buf, 1000, live_hosts_file)) {
465                   char* host = strtok(buf, " \t\n\r");  // strip the line
466                   if (host)
467                           live_hosts.insert(host);
468           }
469
470           fclose(live_hosts_file);
471   }
472
473
474
475 // IfqParserdebug = 1;
476
477   FILE *resfile = fopen(fname.c_str(),"r");
478   if(resfile == NULL){
479         err="Error, can't open "+fname+", error is ";
480         err+=strerror(errno); err+="\n";
481         return(1);
482   }
483
484 //  rpd = new resparse_data(parser);
485   rpd = new resparse_data(use_live_hosts_file, &live_hosts, disributed_mode);
486   rpd_ptr = rpd;
487
488   ResParser_setfileinput(resfile);
489   if(ResParserparse()){
490         err = "ERROR, interface query parse failed.\n";
491         return(1);
492   }
493
494 /*
495   XML_SetUserData(parser, rpd);
496   XML_SetElementHandler(parser, startElement, endElement);
497   do {
498     size_t len = fread(buf, 1, sizeof(buf), resfile);
499     done = len < sizeof(buf);
500     if (!XML_Parse(parser, buf, len, done)) {
501       sprintf(errbuf,
502               "%s at line %d\n",
503               XML_ErrorString(XML_GetErrorCode(parser)),
504               XML_GetCurrentLineNumber(parser));
505                 err=errbuf;
506       return 1;
507     }
508   } while (!done);
509   XML_ParserFree(parser);
510
511   if(rpd->failed()){
512         err = "Interface resource parse failed, exiting.\n";
513   }
514 */
515
516   fclose(resfile);
517
518   return(0);
519
520 }
521
522 int ifq_t::load_ifqs(string fname, string &err){
523   char err_buf[1000];
524   err="";
525
526   FILE *qfile = fopen(fname.c_str(),"r");
527   if(qfile == NULL){
528         sprintf(err_buf, "ERROR, can't open %s, error is %s\n",fname.c_str(),strerror(errno));
529         err=err_buf;
530         return(1);
531   }
532
533   ifq_parse_result = new fta_parse_t();
534   IfqParser_setfileinput(qfile);
535   if(IfqParserparse()){
536         err = "ERROR, interface query parse failed.\n";
537         return(1);
538   }
539
540   vector<table_exp_t *> ifqlist = ifq_parse_result->parse_tree_list->qlist;
541   int i;
542   bool dup = false;
543   for(i=0;i<ifqlist.size();++i){
544         string nm = ifqlist[i]->nmap["name"];
545         if(ifq_map.count(nm)){
546                 err += "ERROR, Duplicate interface query "+nm+"\n";
547                 dup = true;
548         }
549         ifq_map[nm] = ifqlist[i]->wh;
550   }
551
552
553   if(dup) return(1);
554   return(0);
555 }
556
557
558 vector<pair<string,string> > ifq_t::eval(string qname, int &err_no){
559         vector<pair<string,string> > retval;
560         err_no = 0;
561
562         if(ifq_map.count(qname) == 0){
563                 err_no = 1;
564                 return retval;
565         }
566         if(rpd->failed()){
567                 err_no = 2;
568                 return retval;
569         }
570
571         return rpd->find_ifaces(ifq_map[qname]);
572
573 }
574
575 vector<string> ifq_t::get_iface_vals(string host_name, string basic_if_name, string property, int &err_no, string &err_str){
576         vector<string> retval;
577         err_no = 0;
578
579         char *cdat = strdup(basic_if_name.c_str());
580         int pos;
581         string virtual_iface = "0";
582         string iface_name = basic_if_name;
583         for(pos=strlen(cdat)-1;pos>=0 && isdigit(cdat[pos]);--pos);
584         if(pos>0 && cdat[pos] == 'X' && pos<=strlen(cdat)-2){
585                 cdat[pos] = '\0';
586                 virtual_iface = cdat+pos+1;
587                 iface_name = cdat;
588         }
589         free(cdat);
590
591         if(property == "virtual_interface_id"){
592                 retval.push_back(virtual_iface);
593                 return retval;
594         }
595
596
597         if(rpd->failed()){
598                 err_no = 1; err_str = "interface resource parse failed.";
599                 return retval;
600         }
601
602         vector<int> ifi = rpd->get_ifaces_by_Name(host_name, iface_name);
603         if(ifi.size() == 0){
604                 err_no = 1; err_str="interface not found.";
605                 return retval;
606         }
607         if(ifi.size()>1){
608                 err_no = 1; err_str="multiple interfaces found.";
609                 return retval;
610         }
611
612         return rpd->get_property(ifi[0], property);
613
614 }
615
616 vector<string> ifq_t::get_iface_properties(string host_name, string basic_if_name, int &err_no, string &err_str){
617         vector<string> retval;
618         err_no = 0;
619
620         char *cdat = strdup(basic_if_name.c_str());
621         int pos;
622         string virtual_iface = "0";
623         string iface_name = basic_if_name;
624         for(pos=strlen(cdat)-1;pos>=0 && isdigit(cdat[pos]);--pos);
625         if(pos>0 && cdat[pos] == 'X' && pos<=strlen(cdat)-2){
626                 cdat[pos] = '\0';
627                 virtual_iface = cdat+pos+1;
628                 iface_name = cdat;
629         }
630         free(cdat);
631
632         if(rpd->failed()){
633                 err_no = 1; err_str = "interface resource parse failed.";
634                 return retval;
635         }
636
637         vector<int> ifi = rpd->get_ifaces_by_Name(host_name, iface_name);
638         if(ifi.size() == 0){
639                 err_no = 1; err_str="interface not found.";
640                 return retval;
641         }
642         if(ifi.size()>1){
643                 err_no = 1; err_str="multiple interfaces found.";
644                 return retval;
645         }
646
647         return rpd->get_properties(ifi[0]);
648
649 }