Back to index

nordugrid-arc-nox  1.1.0~rc6
conf_cache.cpp
Go to the documentation of this file.
00001 #include <arc/XMLNode.h>
00002 
00003 #include "conf_cache.h"
00004 
00005 CacheConfig::CacheConfig(std::string username): _cache_max(100),
00006                                                 _cache_min(100),
00007                                                 _log_level("INFO") {
00008   // open conf file
00009   std::ifstream cfile;
00010   if(nordugrid_config_loc().empty()) read_env_vars(true);
00011   if(!config_open(cfile)) throw CacheConfigException("Can't open configuration file");
00012   
00013   /* detect type of file */
00014   switch(config_detect(cfile)) {
00015     case config_file_XML: {
00016       Arc::XMLNode cfg;
00017       if(!cfg.ReadFromStream(cfile)) {
00018         config_close(cfile);
00019         throw CacheConfigException("Can't interpret configuration file as XML");
00020       };
00021       config_close(cfile);
00022       try {
00023         parseXMLConf(username, cfg);
00024       } catch (CacheConfigException& e) {
00025         config_close(cfile);
00026         throw e;
00027       }
00028     }; break;
00029     case config_file_INI: {
00030       ConfigSections* cf = new ConfigSections(cfile);
00031       try {
00032         parseINIConf(username, cf);
00033       } catch (CacheConfigException& e) {
00034         delete cf;
00035         config_close(cfile);
00036         throw e;
00037       }
00038       delete cf;
00039     }; break;
00040     default: {
00041       config_close(cfile);
00042       throw CacheConfigException("Can't recognize type of configuration file");
00043     }; break;
00044   };
00045   config_close(cfile);
00046 }
00047 
00048 void CacheConfig::parseINIConf(std::string username, ConfigSections* cf) {
00049   
00050   cf->AddSection("common");
00051   cf->AddSection("grid-manager");
00052   
00053   for(;;) {
00054     std::string rest;
00055     std::string command;
00056     cf->ReadNext(command,rest);
00057 
00058     if(command.length() == 0) break;
00059     
00060     else if(command == "remotecachedir") {
00061       std::string cache_dir = config_next_arg(rest);
00062       if(cache_dir.length() == 0) continue; // cache is disabled
00063       std::string cache_link_dir = config_next_arg(rest);
00064        
00065       // take off leading slashes
00066       if (cache_dir.rfind("/") == cache_dir.length()-1) cache_dir = cache_dir.substr(0, cache_dir.length()-1);
00067 
00068       // if there are substitutions, check username is defined
00069       if (username.empty() &&
00070           (cache_dir.find("%U") != std::string::npos ||
00071               cache_dir.find("%u") != std::string::npos ||
00072               cache_dir.find("%g") != std::string::npos ||
00073               cache_dir.find("%H") != std::string::npos ||
00074               cache_link_dir.find("%U") != std::string::npos ||  
00075               cache_link_dir.find("%u") != std::string::npos ||
00076               cache_link_dir.find("%g") != std::string::npos ||
00077               cache_link_dir.find("%H") != std::string::npos )) continue; 
00078       // add this cache to our list
00079       std::string cache = cache_dir;
00080       // check if the cache dir needs to be drained 
00081       bool isDrainingCache = false;
00082       if (cache_link_dir == "drain") {
00083         cache = cache_dir.substr(0, cache_dir.find(" "));
00084         cache_link_dir = "";
00085         isDrainingCache = true;
00086       }
00087       if (!cache_link_dir.empty()) cache += " "+cache_link_dir;
00088    
00089       if(isDrainingCache)
00090         _draining_cache_dirs.push_back(cache);  
00091       else
00092         _remote_cache_dirs.push_back(cache);
00093     }
00094     else if(command == "cachedir") {
00095       std::string cache_dir = config_next_arg(rest);
00096       if(cache_dir.length() == 0) continue; // cache is disabled
00097       std::string cache_link_dir = config_next_arg(rest);
00098 
00099       // validation of paths
00100       while (cache_dir.length() > 1 && cache_dir.rfind("/") == cache_dir.length()-1) cache_dir = cache_dir.substr(0, cache_dir.length()-1);
00101       if (cache_dir[0] != '/') throw CacheConfigException("Cache path must start with '/'");
00102       if (cache_dir.find("..") != std::string::npos) throw CacheConfigException("Cache path cannot contain '..'");
00103       if (!cache_link_dir.empty() && cache_link_dir != "." && cache_link_dir != "drain") {
00104         while (cache_link_dir.rfind("/") == cache_link_dir.length()-1) cache_link_dir = cache_link_dir.substr(0, cache_link_dir.length()-1);
00105         if (cache_link_dir[0] != '/') throw CacheConfigException("Cache link path must start with '/'");
00106         if (cache_link_dir.find("..") != std::string::npos) throw CacheConfigException("Cache link path cannot contain '..'");
00107       }
00108       
00109       // if there are substitutions, check username is defined
00110       if (username.empty() &&
00111           (cache_dir.find("%U") != std::string::npos ||
00112               cache_dir.find("%u") != std::string::npos ||
00113               cache_dir.find("%g") != std::string::npos ||
00114               cache_dir.find("%H") != std::string::npos ||
00115               cache_link_dir.find("%U") != std::string::npos ||  
00116               cache_link_dir.find("%u") != std::string::npos ||
00117               cache_link_dir.find("%g") != std::string::npos ||
00118               cache_link_dir.find("%H") != std::string::npos )) continue;
00119 
00120       // add this cache to our list
00121       std::string cache = cache_dir;
00122       bool isDrainingCache = false;
00123       // check if the cache dir needs to be drained 
00124       if (cache_link_dir == "drain") {
00125         cache = cache_dir.substr(0, cache_dir.find(' '));
00126         cache_link_dir = "";
00127         isDrainingCache = true;
00128       }
00129       if (!cache_link_dir.empty())
00130         cache += " "+cache_link_dir;
00131 
00132       if (isDrainingCache)
00133         _draining_cache_dirs.push_back(cache); 
00134       else
00135         _cache_dirs.push_back(cache);
00136     }
00137     else if(command == "cachesize") {
00138       std::string max_s = config_next_arg(rest);
00139       if(max_s.length() == 0)
00140         continue; 
00141 
00142       std::string min_s = config_next_arg(rest);
00143       if(min_s.length() == 0)
00144         throw CacheConfigException("Not enough parameters in cachesize parameter");
00145 
00146       off_t max_i;
00147       if(!Arc::stringto(max_s,max_i))
00148         throw CacheConfigException("bad number in cachesize parameter");
00149       if (max_i > 100 || max_i < 0)
00150         throw CacheConfigException("max cache size must be between 0 and 100");
00151       _cache_max = max_i;
00152       
00153       off_t min_i;
00154       if(!Arc::stringto(min_s,min_i))
00155         throw CacheConfigException("bad number in cachesize parameter");
00156       if (min_i > 100 || min_i < 0)
00157         throw CacheConfigException("max cache size must be between 0 and 100");
00158       if (min_i >= max_i)
00159         throw CacheConfigException("max cache size must be greater than min size");
00160       _cache_min = min_i;
00161     }
00162     else if(command == "cacheloglevel") {
00163       std::string log_level = config_next_arg(rest);
00164       if(log_level.length() == 0)
00165         throw CacheConfigException("No value specified in cacheloglevel");
00166       off_t level_i;
00167       if(!Arc::stringto(log_level, level_i))
00168         throw CacheConfigException("bad number in cacheloglevel parameter");
00169       // manual conversion from int to log level
00170       switch (level_i) {
00171         case 0: { _log_level = "FATAL"; };
00172           break;
00173         case 1: { _log_level = "ERROR"; };
00174           break;
00175         case 2: { _log_level = "WARNING"; };
00176           break;
00177         case 3: { _log_level = "INFO"; };
00178           break;
00179         case 4: { _log_level = "VERBOSE"; };
00180           break;
00181         case 5: { _log_level = "DEBUG"; };
00182           break;
00183         default: { _log_level = "INFO"; };
00184           break;
00185       } 
00186     }
00187     else if(command == "control") {
00188       // if the user specified here matches the one given, exit the loop
00189       config_next_arg(rest);
00190       bool usermatch = false;
00191       std::string user = config_next_arg(rest);
00192       while (user != "") {
00193         if(user == "*") {  /* add all gridmap users */
00194            if(!gridmap_user_list(rest)) throw CacheConfigException("Can't read users in gridmap file " + globus_gridmap());
00195         }
00196         else if (user == username || user == ".") {
00197           usermatch = true;
00198           break;
00199         }
00200         user = config_next_arg(rest);
00201       }
00202       if (usermatch) break;
00203       _cache_dirs.clear();
00204       _cache_max = 100;
00205       _cache_min = 100;
00206     }
00207   }
00208 }
00209 
00210 void CacheConfig::parseXMLConf(std::string username, Arc::XMLNode cfg) { 
00211   /*
00212   control
00213     username
00214     controlDir
00215     sessionRootDir
00216     cache
00217       location
00218         path
00219         link
00220       remotelocation
00221         path
00222         link
00223       highWatermark
00224       lowWatermark
00225       cacheLogLevel
00226     defaultTTL
00227     defaultTTR
00228     maxReruns
00229     noRootPower
00230   */
00231   Arc::XMLNode control_node = cfg["control"];
00232   while (control_node) {
00233     // does this match our username?
00234     std::string user = control_node["username"];
00235     if (user != username && user != ".") {
00236       ++control_node;
00237       continue;
00238     }
00239     Arc::XMLNode cache_node = control_node["cache"];
00240     if(cache_node) {
00241       Arc::XMLNode location_node = cache_node["location"];
00242       for(;location_node;++location_node) {
00243         std::string cache_dir = location_node["path"];
00244         std::string cache_link_dir = location_node["link"];
00245         if(cache_dir.length() == 0) 
00246           throw CacheConfigException("Missing path in cache location element");
00247 
00248         // validation of paths
00249         while (cache_dir.length() > 1 && cache_dir.rfind("/") == cache_dir.length()-1) cache_dir = cache_dir.substr(0, cache_dir.length()-1);
00250         if (cache_dir[0] != '/') throw CacheConfigException("Cache path must start with '/'");
00251         if (cache_dir.find("..") != std::string::npos) throw CacheConfigException("Cache path cannot contain '..'");
00252         if (!cache_link_dir.empty() && cache_link_dir != "." && cache_link_dir != "drain") {
00253           while (cache_link_dir.rfind("/") == cache_link_dir.length()-1) cache_link_dir = cache_link_dir.substr(0, cache_link_dir.length()-1);
00254           if (cache_link_dir[0] != '/') throw CacheConfigException("Cache link path must start with '/'");
00255           if (cache_link_dir.find("..") != std::string::npos) throw CacheConfigException("Cache link path cannot contain '..'");
00256         }
00257       
00258         // if there are user substitutions, check username is defined
00259         if (username.empty() &&
00260             (cache_dir.find("%U") != std::string::npos ||
00261                 cache_dir.find("%u") != std::string::npos ||
00262                 cache_dir.find("%g") != std::string::npos ||
00263                 cache_dir.find("%H") != std::string::npos ||
00264                 cache_link_dir.find("%U") != std::string::npos ||  
00265                 cache_link_dir.find("%u") != std::string::npos ||
00266                 cache_link_dir.find("%g") != std::string::npos ||
00267                 cache_link_dir.find("%H") != std::string::npos )) continue;
00268         
00269         // add this cache to our list
00270         std::string cache = cache_dir;
00271         bool isDrainingCache = false;
00272         // check if the cache dir needs to be drained 
00273         if (cache_link_dir == "drain") {
00274           cache = cache_dir.substr(0, cache_dir.find (" "));
00275           cache_link_dir = "";
00276           isDrainingCache = true;
00277         }
00278   
00279         if (!cache_link_dir.empty())
00280           cache += " "+cache_link_dir;
00281 
00282         // TODO: handle paths with spaces
00283         if(isDrainingCache)
00284           _draining_cache_dirs.push_back(cache); 
00285         else
00286           _cache_dirs.push_back(cache);
00287       }
00288       Arc::XMLNode high_node = cache_node["highWatermark"];
00289       Arc::XMLNode low_node = cache_node["lowWatermark"];
00290       if (high_node && !low_node) {
00291         throw CacheConfigException("missing lowWatermark parameter");
00292       } else if (low_node && !high_node) {
00293         throw CacheConfigException("missing highWatermark parameter");
00294       } else if (low_node && high_node) {
00295         off_t max_i;
00296         if(!Arc::stringto((std::string)high_node,max_i))
00297           throw CacheConfigException("bad number in highWatermark parameter");
00298         if (max_i > 100)
00299           throw CacheConfigException("number is too high in highWatermark parameter");
00300         _cache_max = max_i;
00301 
00302         off_t min_i;
00303         if(!Arc::stringto((std::string)low_node,min_i))
00304           throw CacheConfigException("bad number in lowWatermark parameter");
00305         if (min_i > 100)
00306           throw CacheConfigException("number is too high in lowWatermark parameter");
00307         if (min_i >= max_i)
00308           throw CacheConfigException("highWatermark must be greater than lowWatermark");
00309         _cache_min = min_i;
00310       }
00311       std::string cache_log_level = cache_node["cacheLogLevel"];
00312       if (!cache_log_level.empty())
00313         _log_level = cache_log_level;
00314       Arc::XMLNode remote_location_node = cache_node["remotelocation"];
00315       for(;remote_location_node;++remote_location_node) {
00316         std::string cache_dir = remote_location_node["path"];
00317         std::string cache_link_dir = remote_location_node["link"];
00318         if(cache_dir.length() == 0) 
00319           throw CacheConfigException("Missing path in remote cache location element");
00320 
00321         // validation of paths
00322         while (cache_dir.length() > 1 && cache_dir.rfind("/") == cache_dir.length()-1) cache_dir = cache_dir.substr(0, cache_dir.length()-1);
00323         if (cache_dir[0] != '/') throw CacheConfigException("Remote cache path must start with '/'");
00324         if (cache_dir.find("..") != std::string::npos) throw CacheConfigException("Remote cache path cannot contain '..'");
00325         if (!cache_link_dir.empty() && cache_link_dir != "." && cache_link_dir != "drain" && cache_link_dir != "replicate") {
00326           while (cache_link_dir.rfind("/") == cache_link_dir.length()-1) cache_link_dir = cache_link_dir.substr(0, cache_link_dir.length()-1);
00327           if (cache_link_dir[0] != '/') throw CacheConfigException("Remote cache link path must start with '/'");
00328           if (cache_link_dir.find("..") != std::string::npos) throw CacheConfigException("Remote cache link path cannot contain '..'");
00329         }
00330       
00331         // if there are user substitutions, check username is defined
00332         if (username.empty() &&
00333             (cache_dir.find("%U") != std::string::npos ||
00334                 cache_dir.find("%u") != std::string::npos ||
00335                 cache_dir.find("%g") != std::string::npos ||
00336                 cache_dir.find("%H") != std::string::npos ||
00337                 cache_link_dir.find("%U") != std::string::npos ||  
00338                 cache_link_dir.find("%u") != std::string::npos ||
00339                 cache_link_dir.find("%g") != std::string::npos ||
00340                 cache_link_dir.find("%H") != std::string::npos )) continue;
00341         
00342         // add this cache to our list
00343         std::string cache = cache_dir;
00344         bool isDrainingCache = false;
00345         // check if the cache dir needs to be drained 
00346         if (cache_link_dir == "drain") {
00347           cache = cache_dir.substr(0, cache_dir.find (" "));
00348           cache_link_dir = "";
00349           isDrainingCache = true;
00350         }
00351   
00352         if (!cache_link_dir.empty())
00353           cache += " "+cache_link_dir;
00354 
00355         // TODO: handle paths with spaces
00356         if(isDrainingCache)
00357           _draining_cache_dirs.push_back(cache); 
00358         else
00359           _remote_cache_dirs.push_back(cache);
00360       }
00361     } else {
00362       // cache is disabled
00363     }
00364     ++control_node;
00365   }
00366 }
00367