Back to index

nordugrid-arc-nox  1.1.0~rc6
configurator.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <fstream>
00006 #include <vector>
00007 #include <glibmm.h>
00008 #include <arc/StringConv.h>
00009 #include <arc/ArcRegex.h>
00010 #include <arc/message/PayloadRaw.h>
00011 
00012 #include "configurator.h"
00013 #include "job.h"
00014 
00015 namespace Paul
00016 {
00017 
00018 Configurator::Configurator(Arc::Config *cfg):logger_(Arc::Logger::rootLogger, "Paul::Configurator"),cfg_(*cfg) { 
00019     cfg_.setFileName(cfg->getFileName());
00020 };
00021 
00022 int
00023 Configurator::getPeriod(void)
00024 {
00025     return Arc::stringtoi((std::string)cfg_["RequestPeriod"]);
00026 }
00027 
00028 Arc::XMLNode 
00029 Configurator::getApplicationEnvironments(void)
00030 {
00031     return cfg_["glue2:ApplicationEnvironments"];
00032 }
00033 
00034 std::map<std::string, std::string> 
00035 Configurator::getPki(void)
00036 {
00037     std::map<std::string, std::string> out;
00038     out["CertificatePath"] = (std::string)cfg_["CertificatePath"];
00039     out["PrivateKey"] = (std::string)cfg_["PrivateKey"];
00040     out["CACertificatePath"] = (std::string)cfg_["CACertificatePath"];
00041     out["CACertificatesDir"] = (std::string)cfg_["CACertificatesDir"];
00042     return out;
00043 }
00044 
00045 std::vector<std::string> 
00046 Configurator::getSchedulers(void)
00047 {
00048     std::vector<std::string> out;
00049     Arc::XMLNode sched_ep;
00050     for (int i = 0; (sched_ep = cfg_["SchedulerEndpoint"][i]) != false; i++) {
00051         std::string sched_endpoint = (std::string)sched_ep;
00052         out.push_back(sched_endpoint);
00053     }
00054     return out;
00055 }
00056 
00057 std::string 
00058 Configurator::getCachePath(void)
00059 {
00060     return (std::string)cfg_["CacheDirectoryPath"];
00061 }
00062 
00063 std::string 
00064 Configurator::getEndpoint(void) 
00065 {
00066     return (std::string)cfg_["Endpoint"];
00067 }
00068 
00069 std::string
00070 Configurator::getJobRoot(void)
00071 {
00072     return (std::string)cfg_["JobRoot"];
00073 }
00074 
00075 HTMLRequest::HTMLRequest(Arc::Message &in)
00076 {
00077     method = in.Attributes()->get("HTTP:METHOD");
00078     path = in.Attributes()->get("PLEXER:EXTENSION");
00079     
00080     // collect POST values
00081     if (method == "POST") {
00082         Arc::PayloadRawInterface *in_payload = NULL;
00083         try {
00084             in_payload = dynamic_cast<Arc::PayloadRawInterface *>(in.Payload());
00085         } catch (std::exception &e) {
00086             throw InvalidMessageException();
00087         }
00088         // parse post values
00089         std::string post_content = in_payload->Content();
00090         // here assume the post value is in  one line 
00091         std::vector<std::string> lines;
00092         Arc::tokenize(post_content, lines, "&");
00093         for (int i = 0; i < lines.size(); i++) {
00094             std::vector<std::string> key_value;
00095             Arc::tokenize(lines[i], key_value, "=");
00096             if (key_value.size() >= 1) {
00097                 std::string v = Arc::uri_unescape(Glib::strcompress(key_value[1]));
00098                 POST[key_value[0]] = v; 
00099             }
00100         }
00101     }
00102     // set base_path
00103     std::string endpoint = in.Attributes()->get("HTTP:ENDPOINT");
00104     base_path = endpoint.substr(0, endpoint.rfind(path));
00105     if (base_path[base_path.size()] != '/') {
00106         base_path += '/';
00107     }
00108 }
00109 
00110 void
00111 Configurator::style(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00112 {
00113     response += Glib::file_get_contents("style.css");
00114     response.content_type = "text/plain";
00115 }
00116 
00117 void 
00118 Configurator::index(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00119 {
00120     response += response.header;
00121     response += "<ul>";
00122     response += "<li><a href=\"" + request.base_path + "jobs/\">Jobs</a></li>";
00123     response += "<li><a href=\"" + request.base_path + "conf/\">Basic Coniguration Options</a></li>";
00124     response += "<li><a href=\"" + request.base_path + "sched/\">Schedulers</a></li>";
00125     response += "<li><a href=\"" + request.base_path + "rte/\">Application Environments</a></li>";
00126     response += "<li><a href=\"" + request.base_path + "log/\">Log messages</a></li>";
00127     response += "</ul>";
00128     response += response.footer;
00129 }
00130 
00131 void 
00132 Configurator::conf(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00133 {
00134     response += response.header;
00135     response += "<div id=\"content-table\">";
00136     response += "<table border=\"0\" cellpading=\"5px\" cellspacing=\"5px\">";
00137     response += "<tr><td>Period (s)</td><td>" + Arc::tostring(self->getPeriod()) + "</td></tr>";
00138     response += "<tr><td>Job root directory</td><td>" + self->getJobRoot() + "</td></tr>";
00139     response += "<tr><td>Client certificate path</td><td>" + self->getPki()["CertificatePath"] + "</td></tr>";
00140     response += "<tr><td>Client private key path</td><td>" + self->getPki()["PrivateKey"] + "</td></tr>";
00141     response += "<tr><td>Accepted CAs path</td><td>" + self->getPki()["CACertificatePath"] + "</td></tr>";
00142     response += "</table></div>";
00143     response += response.footer;
00144 }
00145 
00146 void 
00147 Configurator::sched(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00148 {
00149     response += response.header;
00150     response += "<div id=\"content-div\"> \
00151                     <div id=\"content-title\"> \
00152                         <div id=\"button\"><a href=\"" + request.base_path + "sched/add/\">add</a></div> \
00153                         <div id=\"title-name\"><h2>Current Schedulers</h2></div> \
00154                     </div>";
00155     response += "<div id=\"content-content\"><table border=\"0\" cellpadding=\"5px\" cellspacing=\"5px\" width=\"100%\">";
00156     response += "<tr><th>URL</th><th>Actions</th></tr>";
00157     std::vector<std::string> schedulers = self->getSchedulers();
00158     for (int i = 0; i < schedulers.size(); i++) {
00159         response += "<tr><td width=\"100%\">" + schedulers[i] + "</td><td><a href=\"" + request.base_path + "sched/del/" + Arc::tostring(i) + "/\">delete</a></td></tr>";
00160     }
00161     response += "</table></div></div>";
00162     response += response.footer;
00163 }
00164 
00165 void 
00166 Configurator::sched_add(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00167 {
00168     response += response.header;
00169     if (request.method == "GET") {
00170         // show form
00171         response += "<div id=\"content-div\"> \
00172                     <div id=\"content-title\"> \
00173                         <div id=\"title-name\"><h2>Add Scheduler</h2></div> \
00174                     </div>";
00175         response += "<div id=\"content-content\">";
00176         response += "<form action=\".\" method=\"post\">";
00177         response += "<p><label>URL:</label><input type=\"text\" name=\"sched_url\" id=\"sched_url\"/></p>";
00178         response += "<p><input type=\"submit\" value=\"ADD\"/></p>";
00179         response += "</form>";
00180         response += "</div></div>";
00181     } else if (request.method == "POST") {
00182         // process form
00183         std::string sched_url = request.POST["sched_url"];
00184         if (!sched_url.empty()) {
00185             Arc::Config cfg;
00186             cfg.parse(self->cfg_.getFileName().c_str());
00187             // find service tag
00188             Arc::XMLNode chain = cfg["Chain"];
00189             Arc::XMLNode service;
00190             for (int i = 0; (service = chain["Service"][i]) != false; i++) {
00191                 if ("paul" == (std::string)service.Attribute("name")) {
00192                     break;
00193                 }
00194             }
00195             service.NewChild("paul:SchedulerEndpoint") = sched_url;
00196             cfg.save(self->cfg_.getFileName().c_str());
00197             Arc::Config new_cfg(service, self->cfg_.getFileName());
00198             new_cfg.New(self->cfg_);
00199             response += "<p id=\"msg\">Scheduler url: <b>" + sched_url + "</b> has been added.</p>";
00200             response += "<p><a href=\"" + request.base_path + "sched/\">&#171; Back</a></p>";
00201         }
00202     }
00203     response += response.footer;
00204 }
00205 
00206 void 
00207 Configurator::sched_del(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00208 {
00209     std::vector<std::string> tokens;
00210     Arc::tokenize(request.path, tokens, "/");
00211     self->logger_.msg(Arc::VERBOSE, "** %s", request.path);
00212     response += response.header;
00213     if (tokens.size() == 3) {
00214         int sched_id = Arc::stringtoi(tokens[2]);
00215         Arc::Config cfg;
00216         cfg.parse(self->cfg_.getFileName().c_str());
00217         // find service tag
00218         Arc::XMLNode chain = cfg["Chain"];
00219         Arc::XMLNode service;
00220         for (int i = 0; (service = chain["Service"][i]) != false; i++) {
00221             if ("paul" == (std::string)service.Attribute("name")) {
00222                 break;
00223             }
00224         }
00225         Arc::XMLNode sched;
00226         std::vector<std::string> schedulers = self->getSchedulers();
00227         for (int i = 0; (sched = service["SchedulerEndpoint"][i]) != false; i++) {
00228             if (schedulers[sched_id] == (std::string)sched) {
00229                sched.Destroy();
00230             }
00231         }
00232         cfg.save(self->cfg_.getFileName().c_str());
00233         Arc::Config new_cfg(service, self->cfg_.getFileName());
00234         response += "<p id=\"msg\"><b>" + self->getSchedulers()[sched_id] + "</b> has been removed.</p>";
00235         new_cfg.New(self->cfg_);
00236     } else {
00237         response += "<p style=\"err_msg\">No such scheduler!</p>";
00238     }
00239     response += "<p><a href=\"" + request.base_path + "sched/\">&#171; Back</a></p>";
00240     response += response.footer;
00241 }
00242 
00243 std::string 
00244 tail(std::string file_name, int line_n)
00245 {
00246     std::ifstream fin(file_name.c_str(), std::ios::binary);
00247     int ln = 0;
00248     int seek_size = 1024;
00249     std::list<std::string> lines;
00250     fin.seekg(0, std::ios::end);
00251     int block_end = fin.tellg(); 
00252     if (block_end == -1) {
00253         return "";
00254     }
00255     fin.seekg(-seek_size, std::ios::end);
00256     int pos = fin.tellg();
00257     if (pos == -1) {
00258         return "";
00259     }
00260     int block_start = pos;
00261 
00262 /*
00263     std::cout << "bs: " << block_start << std::endl;
00264     std::cout << "p: " << pos << std::endl;
00265     std::cout << "be: " << block_end << std::endl;
00266 */    
00267     std::vector<std::string> tokens;
00268     char buffer[1024];
00269     for(;;) { 
00270         memset(buffer, 0, sizeof(buffer));
00271         fin.read(buffer, sizeof(buffer));
00272         buffer[sizeof(buffer) - 1] = '\0';
00273         std::string l = buffer;
00274         tokens.clear();
00275         Arc::tokenize(l, tokens, "\n");
00276         for (int i = tokens.size()-1 ; i >= 0; i--) {
00277 // std::cout << "**" << tokens[i] << "(" << i << "/" << tokens.size() << ")" << std::endl;
00278             if (i != 0) {
00279                 lines.push_back(tokens[i] + "\n");
00280                 ln++;
00281             } else {
00282                 lines.push_back(tokens[i]);
00283             }
00284         }
00285         if (ln >= line_n) {
00286             break;
00287         }
00288         pos = fin.tellg();
00289 // std::cout << pos << std::endl;
00290         if (pos == -1) {
00291             pos = block_end;
00292         }
00293         if ((fin.eof() && ln < line_n) || pos >= block_end) {
00294             if (block_start == 0) {
00295                 break;
00296             }
00297             block_end = block_start;
00298             int s = block_start - seek_size;
00299             if (s < 0) {
00300                 s = 0;
00301             }
00302             fin.seekg(s, std::ios::beg);
00303             block_start = fin.tellg();
00304             if (block_start == -1) {
00305                 break; 
00306             }
00307         }
00308 /*
00309     std::cout << "bs: " << block_start << std::endl;
00310     std::cout << "p: " << pos << std::endl;
00311     std::cout << "be: " << block_end << std::endl;
00312 */
00313     }
00314     fin.close();
00315     std::list<std::string>::iterator it;
00316     std::string out;
00317     std::string prev;
00318     for (it = lines.begin(); it != lines.end(); it++) {
00319         std::string l = *it;
00320         if (l[l.size() - 1] != '\n') {
00321             prev = l;
00322         } else {
00323             if (!prev.empty()) {
00324                 l += prev;
00325                 prev.clear();
00326             }
00327             out += ("<p class=\"log\">" + l + "</p>");
00328         }
00329     }
00330     return out;
00331 }
00332 
00333 void
00334 Configurator::log(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00335 {
00336     response += response.header;
00337     Arc::Config cfg;
00338     cfg.parse(self->cfg_.getFileName().c_str());
00339     std::string filename = (std::string)cfg["Server"]["Logger"];
00340     if (!filename.empty()) {
00341         response += tail(filename, 100); 
00342     }
00343     response += response.footer;
00344 }
00345 
00346 void
00347 Configurator::rte(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00348 {
00349     response += response.header;
00350     response += "<div id=\"content-div\"> \
00351                     <div id=\"content-title\"> \
00352                         <div id=\"button\"><a href=\"" + request.base_path + "rte/add/\">add</a></div> \
00353                         <div id=\"title-name\"><h2>Current Application Environments</h2></div> \
00354                     </div>";
00355     response += "<div id=\"content-content\"><table border=\"0\" cellpadding=\"5px\" cellspacing=\"5px\" width=\"100%\">";
00356     response += "<tr><th>Name</th><th>Version</th><th>Actions</th></tr>";
00357     Arc::XMLNode rtes = self->getApplicationEnvironments();
00358     Arc::XMLNode rte;
00359     for (int i = 0; (rte = rtes["ApplicationEnvironment"][i]) != false; i++) {
00360         response += "<tr><td>" + (std::string)rte["Name"] + "</td><td>" + (std::string)rte["Version"] + "</td><td><a href=\"" + request.base_path + "rte/del/" + Arc::tostring(i) + "/\">delete</a></td></tr>";
00361     }
00362     response += "</table></div></div>";
00363     response += response.footer;
00364 }
00365 
00366 void
00367 Configurator::rte_add(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00368 {
00369     response += response.header;
00370     if (request.method == "GET") {
00371         // show form
00372         response += "<div id=\"content-div\"> \
00373                     <div id=\"content-title\"> \
00374                         <div id=\"title-name\"><h2>Add Application Environment</h2></div> \
00375                     </div>";
00376         response += "<div id=\"content-content\">";
00377         response += "<form action=\".\" method=\"post\">";
00378         response += "<p><label>Name: </label><input type=\"text\" name=\"rte_name\" id=\"rte_name\"/></p>";
00379         response += "<p><label>Version: </label><input type=\"text\" name=\"rte_version\" id=\"rte_version\"/></p>";
00380         response += "<p><input type=\"submit\" value=\"ADD\"/></p>";
00381         response += "</form>";
00382         response += "</div></div>";
00383     } else if (request.method == "POST") {
00384         // process form
00385         std::string rte_name = request.POST["rte_name"];
00386         std::string rte_version = request.POST["rte_version"];
00387         if (!rte_name.empty()) {
00388             Arc::Config cfg;
00389             cfg.parse(self->cfg_.getFileName().c_str());
00390             // find service tag
00391             Arc::XMLNode chain = cfg["Chain"];
00392             Arc::XMLNode service;
00393             for (int i = 0; (service = chain["Service"][i]) != false; i++) {
00394                 if ("paul" == (std::string)service.Attribute("name")) {
00395                     break;
00396                 }
00397             }
00398             Arc::XMLNode rtes = service["ApplicationEnvironments"];
00399             // XXX get glue2 namespace
00400             Arc::XMLNode r = rtes.NewChild("glue2:ApplicationEnvironment");
00401             r.NewChild("glue2:Name") = rte_name;
00402             r.NewChild("glue2:Version") = rte_version;
00403             cfg.save(self->cfg_.getFileName().c_str());
00404             Arc::Config new_cfg(service, self->cfg_.getFileName());
00405             new_cfg.New(self->cfg_);
00406             response += "<p id=\"msg\">Application Environment: <b>" + rte_name + "</b> has been added.</p>";
00407             response += "<p><a href=\"" + request.base_path + "rte/\">&#171; Back</a></p>";
00408         }
00409     }
00410     response += response.footer;
00411 }
00412 
00413 void
00414 Configurator::rte_del(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00415 {
00416     std::vector<std::string> tokens;
00417     Arc::tokenize(request.path, tokens, "/");
00418     response += response.header;
00419     if (tokens.size() == 3) {
00420         int rte_id = Arc::stringtoi(tokens[2]);
00421         Arc::Config cfg;
00422         cfg.parse(self->cfg_.getFileName().c_str());
00423         // find service tag
00424         Arc::XMLNode chain = cfg["Chain"];
00425         Arc::XMLNode service;
00426         for (int i = 0; (service = chain["Service"][i]) != false; i++) {
00427             if ("paul" == (std::string)service.Attribute("name")) {
00428                 break;
00429             }
00430         }
00431         Arc::XMLNode rtes = service["ApplicationEnvironments"];
00432         Arc::XMLNode rte = rtes["ApplicationEnvironment"][rte_id];
00433         if (rte != false) {
00434             rte.Destroy();
00435         }
00436         cfg.save(self->cfg_.getFileName().c_str());
00437         Arc::Config new_cfg(service, self->cfg_.getFileName());
00438         response += "<p id=\"msg\">Application Environment has been removed.</p>";
00439         new_cfg.New(self->cfg_);
00440     } else {
00441         response += "<p style=\"err_msg\">No such Application Environment!</p>";
00442     }
00443     response += "<p><a href=\"" + request.base_path + "rte/\">&#171; Back</a></p>";
00444     response += response.footer;
00445 }
00446 
00447 void 
00448 Configurator::jobs(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00449 {
00450     response += response.header;
00451     response += "<div id=\"content-div\"> \
00452                     <div id=\"content-title\"> \
00453                         <div id=\"title-name\"><h2>Current Jobs</h2></div> \
00454                     </div>";
00455     response += "<div id=\"content-content\"><table border=\"0\" cellpadding=\"5px\" cellspacing=\"5px\" width=\"100%\">";
00456     response += "<tr><th>UUID</th><th>Name</th><th>Status</th><th>Scheduler</th><th>Actions</th></tr>";
00457     std::map<const std::string, Job *> all = self->getJobQueue()->getAllJobs();
00458     std::map<const std::string, Job *>::iterator it;
00459     for (it = all.begin(); it != all.end(); it++) {
00460         Job *j = it->second;
00461         std::string s = sched_status_to_string(j->getStatus());
00462         std::string id = j->getID();
00463         std::string name = j->getJobRequest().getName();
00464         std::string sched_url = j->getResourceID();
00465         response += "<tr><td>" + id + "</td><td>" + name + "</td><td>" + s + "</td><td>" + sched_url + "</td><td> \
00466                     <a href=\"" + request.base_path + "job/" + id + "/\">detail</a> | \
00467                     <a href=\"" + request.base_path + "job/stop/" + id + "/\">stop</a></td></tr>";
00468     }
00469     response += "</table></div></div>";
00470     response += response.footer;
00471 }
00472 
00473 void 
00474 Configurator::job(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00475 {
00476 }
00477 
00478 void 
00479 Configurator::job_stop(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00480 {
00481 }
00482 
00483 void
00484 Configurator::icon(Configurator *self, HTMLRequest &request, HTMLResponse &response)
00485 {
00486     // XXX read arc.ico if exist and return it
00487 }
00488 
00489 
00490 Arc::MCC_Status
00491 Configurator::process(Arc::Message &in, Arc::Message &out)
00492 {
00493 
00494     Controller ctrl;
00495     ctrl.insert(std::make_pair("^$", &index));
00496     ctrl.insert(std::make_pair("^/$", &index));
00497     ctrl.insert(std::make_pair("^/style/$", &style));
00498     ctrl.insert(std::make_pair("^/icon/$", &icon));
00499     ctrl.insert(std::make_pair("^/conf/$", &conf));
00500     ctrl.insert(std::make_pair("^/sched/$", &sched));
00501     ctrl.insert(std::make_pair("^/sched/add/$", &sched_add));
00502     ctrl.insert(std::make_pair("^/sched/del/[0-9]*/$", &sched_del));
00503     ctrl.insert(std::make_pair("^/log/$", &log));
00504     ctrl.insert(std::make_pair("^/rte/$", &rte));
00505     ctrl.insert(std::make_pair("^/rte/add/$", &rte_add));
00506     ctrl.insert(std::make_pair("^/rte/del/[0-9]*/$", &rte_del));
00507     ctrl.insert(std::make_pair("^/jobs/$", &jobs));
00508     ctrl.insert(std::make_pair("^/job/[a-f0-9\\\\-]*/$", &job));
00509     ctrl.insert(std::make_pair("^/job/stop/[a-f0-9\\\\-]*/$", &job_stop));
00510 
00511     HTMLRequest request(in);
00512     Arc::PayloadRaw *out_buf = new Arc::PayloadRaw;
00513     if (!out_buf) {
00514         logger_.msg(Arc::ERROR, "Cannot allocate output raw buffer");
00515         return Arc::MCC_Status();
00516     }
00517     Controller::iterator it;
00518     for (it = ctrl.begin(); it != ctrl.end(); it++) {
00519         Arc::RegularExpression r(it->first);
00520         if (r.match(request.path) == true) {
00521             HTMLResponse response;
00522             // set html header
00523             response.header = "<html><head>\
00524                 <title>ARC - Paul Service Configurator</title>\
00525                 <link rel=\"stylesheet\" type=\"text/css\" href=\"" + request.base_path + "style/\"/>\
00526                 <link rel=\"shortcut icon\" href=\"" + request.base_path + "icon/\"/>\
00527                 </head>\
00528                 <body>\
00529                 <div id=\"header\"><h1><a href=\"" + request.base_path + "\"/>ARC - Paul Service Configurator</a></h1></div>\
00530                 <div id=\"content\">";
00531             // set footer
00532             response.footer = "</div></body></html>";
00533             // call viewer function
00534             (*(it->second))(this, request, response);
00535             // generate output message
00536             out_buf->Insert(response.html.c_str(), 0, response.html.length());
00537             out.Payload(out_buf);
00538             out.Attributes()->set("HTTP:content-type", response.content_type);
00539             return Arc::MCC_Status(Arc::STATUS_OK);
00540         }
00541     }
00542     std::string html_error = "<body><html><h1>Page not found</h1></html></body>";
00543     out_buf->Insert(html_error.c_str(), 0, html_error.length());
00544     out.Payload(out_buf);
00545     out.Attributes()->set("HTTP:content-type", "text/html");
00546     // XXX how to set HTTP 404?
00547     return Arc::MCC_Status(Arc::STATUS_OK);
00548 
00549 #if 0
00550     if (client_host != "127.0.0.1") {
00551         logger_.msg(Arc::ERROR, "Permission denied from %s host", client_host);
00552         return Arc::MCC_Status();
00553     }
00554 #endif
00555 }
00556 
00557 } // namespace Paul