main.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jliball.hpp"
  15. #include "XMLTags.h"
  16. #include "configengcallback.hpp"
  17. #include "deploy.hpp"
  18. #include "build-config.h"
  19. #define STANDARD_INDIR COMPONENTFILES_DIR"/configxml"
  20. #define STANDARD_OUTDIR RUNTIME_DIR
  21. void usage()
  22. {
  23. const char* version = "1.1";
  24. printf("HPCC Systems configuration generator. version %s. Usage:\n", version);
  25. puts(" configgen -env <environment file> -ip <ip addr> [options]");
  26. puts("");
  27. puts("options: ");
  28. puts(" -env : The configuration environment to be parsed.");
  29. puts(" -ip : The ip address that will be matched against a component ");
  30. puts(" instance's ip address. If matched, configuration files are ");
  31. puts(" generated for that component");
  32. puts(" -c <component name>: Optional component name for which the ");
  33. puts(" configuration is generated. If -t is also specified, it is ");
  34. puts(" ignored");
  35. puts(" -t <component type>: Optional component type for which the ");
  36. puts(" configuration is generated. If -c is also specified, the ");
  37. puts(" component name is used");
  38. puts(" -id <input directory>: The input directory for the supporting ");
  39. puts(" xml environment files like xsd's, xsl's and ");
  40. puts(" configgencomplist.xml. If not specified, the following ");
  41. puts(" defaults are used. ");
  42. puts(" For win32, 'c:\\trunk\\initfiles\\componentfiles\\configxml'");
  43. puts(" For Linux, '"COMPONENTFILES_DIR"/configxml/'");
  44. puts(" -od <output directory>: The output directory for the generated files.");
  45. puts(" If not specified, the following defaults are used. ");
  46. puts(" For win32, '.'");
  47. puts(" For Linux, '"CONFIG_DIR"'");
  48. puts(" -list: Lists out the components for a specific ip in the format");
  49. puts(" componentType=componentName;config file directory. Does not ");
  50. puts(" generate any output files. If masters and slaves exist for ");
  51. puts(" a component like Roxie or thor, then only the master entry ");
  52. puts(" is returned. ");
  53. puts(" -listall: Lists out all the components specified in the environment");
  54. puts(" that have an instance defined. Does not require an ip. Does ");
  55. puts(" not generate any output files. Output is written to stdout ");
  56. puts(" in the csv format as follows");
  57. puts(" ProcessType,componentNameinstanceip,instanceport,runtimedir,logdir");
  58. puts(" Missing fields will be empty.");
  59. puts(" -listdirs: Lists out any directories that need to be created during ");
  60. puts(" init time. Currently, directories for any drop zones ");
  61. puts(" with the same ip as the -ip option are returned. Format is ");
  62. puts(" one directory per line.");
  63. puts(" -listdropzones: Lists out all the dropzones defined in the environment ");
  64. puts(" Does not require an ip. Does not generate any output files.");
  65. puts(" Output is written to stdout. Format is as follows,");
  66. puts(" one entry per line");
  67. puts(" dropzone node ip,dropzone directory");
  68. puts(" -listcommondirs: Lists out all directories that are listed under ");
  69. puts(" Software/Directories section in the following format. ");
  70. puts(" <CategoryName>=<DirectoryValue>");
  71. puts(" Each directory will be listed on a new line.");
  72. puts(" -machines: Lists out all names or ips of machines specified in the environment");
  73. puts(" Output is written to stdout, one machine per line.");
  74. puts(" -validateonly: Validates the environment, without generating permanent ");
  75. puts(" configurations. Returns 0 if environment is valid and non zero ");
  76. puts(" in other cases. Validation errors are printed to stderr.");
  77. puts(" Ignores -od flag, if supplied.");
  78. puts(" -v : Print verbose output to stdout");
  79. puts(" -help: print out this usage.");
  80. }
  81. void deleteRecursive(const char* path)
  82. {
  83. Owned<IFile> pDir = createIFile(path);
  84. if (pDir->exists())
  85. {
  86. if (pDir->isDirectory())
  87. {
  88. Owned<IDirectoryIterator> it = pDir->directoryFiles(NULL, false, true);
  89. ForEach(*it)
  90. {
  91. StringBuffer name;
  92. it->getName(name);
  93. StringBuffer childPath(path);
  94. childPath.append(PATHSEPCHAR);
  95. childPath.append(name);
  96. deleteRecursive(childPath.str());
  97. }
  98. }
  99. pDir->remove();
  100. }
  101. }
  102. //returns temp path that ends with path sep
  103. //
  104. #ifdef _WIN32
  105. extern DWORD getLastError() { return ::GetLastError(); }
  106. void getTempPath(char* tempPath, unsigned int bufsize, const char* subdir/*=NULL*/)
  107. {
  108. ::GetTempPath(bufsize, tempPath);
  109. ::GetLongPathName(tempPath, tempPath, bufsize);
  110. if (subdir && *subdir)
  111. {
  112. const int len = strlen(tempPath);
  113. char* p = tempPath + len;
  114. strcpy(p, subdir);
  115. p += strlen(subdir);
  116. *p++ = '\\';
  117. *p = '\0';
  118. }
  119. }
  120. #else//Linux specifics follow
  121. extern DWORD getLastError() { return errno; }
  122. void getTempPath(char* tempPath, unsigned int bufsize, const char* subdir/*=NULL*/)
  123. {
  124. assert(bufsize > 5);
  125. strcpy(tempPath, "/tmp/");
  126. if (subdir && *subdir)
  127. {
  128. strcat(tempPath, subdir);
  129. strcat(tempPath, "/");
  130. }
  131. }
  132. #endif
  133. void replaceDotWithHostIp(IPropertyTree* pTree, bool verbose)
  134. {
  135. StringBuffer ip;
  136. queryHostIP().getIpText(ip);
  137. const char* attrs[] = {"@netAddress", "@roxieAddress", "@daliAddress"};
  138. StringBuffer xPath;
  139. for (int i = 0; i < sizeof(attrs)/sizeof(char*); i++)
  140. {
  141. xPath.clear().appendf(".//*[%s]", attrs[i]);
  142. Owned<IPropertyTreeIterator> iter = pTree->getElements(xPath.str());
  143. ForEach(*iter)
  144. {
  145. IPropertyTree* pComponent = &iter->query();
  146. Owned<IAttributeIterator> iAttr = pComponent->getAttributes();
  147. ForEach(*iAttr)
  148. {
  149. const char* attrName = iAttr->queryName();
  150. if (!strcmp(attrName, attrs[i]))
  151. {
  152. String sAttrVal(iAttr->queryValue());
  153. String dot(".");
  154. if (sAttrVal.equals(dot) || sAttrVal.indexOf(".:") == 0 || sAttrVal.indexOf("http://.:") == 0)
  155. {
  156. StringBuffer sb(sAttrVal);
  157. if (sAttrVal.equals(dot))
  158. sb.replaceString(".", ip.str());
  159. else
  160. {
  161. ip.append(":");
  162. sb.replaceString(".:", ip.str());
  163. ip.remove(ip.length() - 1, 1);
  164. }
  165. pComponent->setProp(attrName, sb.str());
  166. if (verbose)
  167. fprintf(stdout, "Replacing '.' with host ip '%s' for component/attribute '%s'[@'%s']\n", ip.str(), pComponent->queryName(), attrName);
  168. }
  169. }
  170. }
  171. }
  172. }
  173. }
  174. int processRequest(const char* in_cfgname, const char* out_dirname, const char* in_dirname,
  175. const char* compName, const char* compType, const char* in_filename,
  176. const char* out_filename, bool generateOutput, const char* ipAddr,
  177. bool listComps, bool verbose, bool listallComps, bool listdirs,
  178. bool listdropzones, bool listcommondirs, bool listMachines, bool validateOnly)
  179. {
  180. Owned<IPropertyTree> pEnv = createPTreeFromXMLFile(in_cfgname);
  181. short nodeIndex = 1;
  182. short index = 1;
  183. short compTypeIndex = 0;
  184. short buildSetIndex = 0;
  185. StringBuffer lastCompAdded;
  186. StringBuffer xPath("*");
  187. CConfigEngCallback callback(verbose);
  188. Owned<IPropertyTreeIterator> iter = pEnv->getElements(xPath.str());
  189. Owned<IConstEnvironment> m_pConstEnvironment;
  190. Owned<IEnvironment> m_pEnvironment;
  191. replaceDotWithHostIp(pEnv, verbose);
  192. StringBuffer envXML;
  193. toXML(pEnv, envXML);
  194. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  195. m_pEnvironment.setown(factory->loadLocalEnvironment(envXML));
  196. m_pConstEnvironment.set(m_pEnvironment);
  197. if (validateOnly)
  198. {
  199. char tempdir[_MAX_PATH];
  200. StringBuffer sb;
  201. while(true)
  202. {
  203. sb.clear().appendf("%d", msTick());
  204. getTempPath(tempdir, sizeof(tempdir), sb.str());
  205. if (!checkDirExists(tempdir))
  206. {
  207. if (recursiveCreateDirectory(tempdir))
  208. break;
  209. }
  210. }
  211. try
  212. {
  213. Owned<IEnvDeploymentEngine> m_configGenMgr;
  214. CConfigEngCallback callback(verbose, true);
  215. m_configGenMgr.setown(createConfigGenMgr(*m_pConstEnvironment, callback, NULL, in_dirname?in_dirname:"", tempdir, NULL, NULL, NULL));
  216. m_configGenMgr->deploy(DEFLAGS_CONFIGFILES, DEBACKUP_NONE, false, false);
  217. deleteRecursive(tempdir);
  218. }
  219. catch(IException* e)
  220. {
  221. deleteRecursive(tempdir);
  222. throw e;
  223. }
  224. }
  225. else if (!listComps && !listallComps && !listdirs && !listdropzones && !listcommondirs && !listMachines)
  226. {
  227. Owned<IEnvDeploymentEngine> m_configGenMgr;
  228. m_configGenMgr.setown(createConfigGenMgr(*m_pConstEnvironment, callback, NULL, in_dirname?in_dirname:"", out_dirname?out_dirname:"", compName, compType, ipAddr));
  229. m_configGenMgr->deploy(DEFLAGS_CONFIGFILES, DEBACKUP_NONE, false, false);
  230. }
  231. else if (listdirs || listdropzones)
  232. {
  233. StringBuffer out;
  234. xPath.clear().appendf("Software/%s", XML_TAG_DROPZONE);
  235. Owned<IPropertyTreeIterator> dropZonesInsts = pEnv->getElements(xPath.str());
  236. ForEach(*dropZonesInsts)
  237. {
  238. IPropertyTree* pDropZone = &dropZonesInsts->query();
  239. StringBuffer computerName(pDropZone->queryProp(XML_ATTR_COMPUTER));
  240. xPath.clear().appendf("Hardware/Computer[@name=\"%s\"]", computerName.str());
  241. IPropertyTree* pComputer = pEnv->queryPropTree(xPath.str());
  242. if (pComputer)
  243. {
  244. const char* netAddr = pComputer->queryProp("@netAddress");
  245. if (listdropzones)
  246. out.appendf("%s,%s\n", netAddr, pDropZone->queryProp(XML_ATTR_DIRECTORY));
  247. else if (matchDeployAddress(ipAddr, netAddr))
  248. out.appendf("%s\n", pDropZone->queryProp(XML_ATTR_DIRECTORY));
  249. }
  250. }
  251. fprintf(stdout, "%s", out.str());
  252. }
  253. else if (listcommondirs)
  254. {
  255. StringBuffer out;
  256. StringBuffer name;
  257. xPath.clear().appendf("Software/Directories/@name");
  258. name.append(pEnv->queryProp(xPath.str()));
  259. xPath.clear().appendf("Software/Directories/Category");
  260. Owned<IPropertyTreeIterator> dirInsts = pEnv->getElements(xPath.str());
  261. ForEach(*dirInsts)
  262. {
  263. IPropertyTree* pDir = &dirInsts->query();
  264. StringBuffer dirName(pDir->queryProp("@dir"));
  265. int len = strrchr(dirName.str(), '/') - dirName.str();
  266. dirName.setLength(len);
  267. if (strstr(dirName.str(), "/[INST]") || strstr(dirName.str(), "/[COMPONENT]"))
  268. continue;
  269. dirName.replaceString("[NAME]", name.str());
  270. out.appendf("%s=%s\n", pDir->queryProp(XML_ATTR_NAME), dirName.str());
  271. }
  272. fprintf(stdout, "%s", out.str());
  273. }
  274. else if (listMachines)
  275. {
  276. StringBuffer out;
  277. Owned<IPropertyTreeIterator> computers = pEnv->getElements("Hardware/Computer");
  278. ForEach(*computers)
  279. {
  280. IPropertyTree* pComputer = &computers->query();
  281. const char *netAddress = pComputer->queryProp("@netAddress");
  282. out.appendf("%s,", netAddress ? netAddress : "");
  283. StringBuffer xpath;
  284. const char *computerType = pComputer->queryProp("@computerType");
  285. if (computerType)
  286. {
  287. xpath.appendf("Hardware/ComputerType[@name='%s']", computerType);
  288. IPropertyTree *pType = pEnv->queryPropTree(xpath.str());
  289. out.appendf("%s", pType->queryProp("@opSys"));
  290. }
  291. out.newline();
  292. }
  293. fprintf(stdout, "%s", out.str());
  294. }
  295. else
  296. {
  297. StringBuffer out;
  298. Owned<IPropertyTree> pSelectedComponents = getInstances(&m_pConstEnvironment->getPTree(), compName, compType, ipAddr, true);
  299. Owned<IPropertyTreeIterator> it = pSelectedComponents->getElements("*");
  300. ForEach(*it)
  301. {
  302. IPropertyTree* pComponent = &it->query();
  303. if (listComps)
  304. {
  305. if (!strcmp(pComponent->queryProp("@buildSet"), "roxie") || !strcmp(pComponent->queryProp("@buildSet"), "thor"))
  306. {
  307. StringBuffer sbChildren;
  308. bool isMaster = false;
  309. Owned<IPropertyTreeIterator> itInst = pComponent->getElements("*");
  310. ForEach(*itInst)
  311. {
  312. IPropertyTree* pInst = &itInst->query();
  313. String instName(pInst->queryName());
  314. if (!strcmp(instName.toCharArray(), "ThorMasterProcess") || instName.startsWith("RoxieServerProcess"))
  315. {
  316. isMaster = true;
  317. out.appendf("%s=%s;%s%c%s;%s\n", pComponent->queryProp("@name"), pComponent->queryProp("@buildSet"), out_dirname, PATHSEPCHAR, pComponent->queryProp("@name"),"master");
  318. }
  319. else if (!strcmp(instName.toCharArray(), "RoxieSlaveProcess"))
  320. sbChildren.appendf("%s=%s;%s%c%s;%s\n", pComponent->queryProp("@name"), pComponent->queryProp("@buildSet"), out_dirname, PATHSEPCHAR, pComponent->queryProp("@name"),"slave");
  321. }
  322. if (!isMaster)
  323. out.append(sbChildren);
  324. }
  325. else
  326. out.appendf("%s=%s;%s%c%s\n", pComponent->queryProp("@name"), pComponent->queryProp("@buildSet"), out_dirname, PATHSEPCHAR, pComponent->queryProp("@name"));
  327. }
  328. else if (listallComps)
  329. {
  330. StringBuffer netAddr;
  331. StringBuffer port;
  332. StringBuffer processName(pComponent->queryName());
  333. bool multiInstances = false;
  334. if(!strcmp(processName.str(), "ThorCluster") || !strcmp(processName.str(), "RoxieCluster"))
  335. {
  336. processName.clear();
  337. multiInstances = true;
  338. }
  339. if (pComponent->numChildren())
  340. {
  341. Owned<IPropertyTreeIterator> itComp = pComponent->getElements("*");
  342. ForEach(*itComp)
  343. {
  344. IPropertyTree* pInst = &itComp->query();
  345. if (!strcmp(pInst->queryName(), "ThorSlaveProcess") || !strcmp(pInst->queryName(), "ThorSpareProcess"))
  346. continue;
  347. netAddr.clear().append(pInst->queryProp("@netAddress"));
  348. port.clear().append(pInst->queryProp("@port"));
  349. if (multiInstances)
  350. processName.clear().append(pInst->queryName());
  351. out.appendf("%s,%s,%s,%s,%s%c%s,%s\n", processName.str(),
  352. pComponent->queryProp("@name"), netAddr.str(), port.str(),
  353. STANDARD_OUTDIR, PATHSEPCHAR, pComponent->queryProp("@name"), pComponent->queryProp("@logDir"));
  354. }
  355. }
  356. else
  357. {
  358. netAddr.clear().append(pComponent->queryProp("@netAddress"));
  359. port.clear().append(pComponent->queryProp("@port"));
  360. out.appendf("%s,%s,%s,%s,%s%c%s,%s\n", pComponent->queryName(),
  361. pComponent->queryProp("@name"), netAddr.str(), port.str(),
  362. STANDARD_OUTDIR, PATHSEPCHAR, pComponent->queryProp("@name"), pComponent->queryProp("@logDir"));
  363. }
  364. }
  365. }
  366. fprintf(stdout, "%s", out.str());
  367. }
  368. return 0;
  369. }
  370. int main(int argc, char** argv)
  371. {
  372. InitModuleObjects();
  373. Owned<IProperties> globals = createProperties(true);
  374. const char* in_filename = NULL;
  375. const char* in_cfgname = NULL;
  376. const char* out_dirname = STANDARD_OUTDIR;
  377. const char* in_dirname = STANDARD_INDIR;
  378. const char* out_filename = NULL;
  379. const char* compName = NULL;
  380. const char* compType = NULL;
  381. StringBuffer ipAddr = NULL;
  382. bool generateOutput = true;
  383. bool listComps = false;
  384. bool verbose = false;
  385. bool listallComps = false;
  386. bool listdirs = false;
  387. bool listdropzones = false;
  388. bool listcommondirs = false;
  389. bool listMachines = false;
  390. bool validateOnly = false;
  391. int i = 1;
  392. bool writeToFiles = false;
  393. int port = 80;
  394. while(i<argc)
  395. {
  396. if(stricmp(argv[i], "-help") == 0 || stricmp(argv[i], "-?") == 0)
  397. {
  398. usage();
  399. releaseAtoms();
  400. return 0;
  401. }
  402. else if (stricmp(argv[i], "-env") == 0)
  403. {
  404. i++;
  405. in_cfgname = argv[i++];
  406. }
  407. else if (stricmp(argv[i], "-c") == 0)
  408. {
  409. i++;
  410. compName = argv[i++];
  411. }
  412. else if (stricmp(argv[i], "-t") == 0)
  413. {
  414. i++;
  415. compType = argv[i++];
  416. }
  417. else if (stricmp(argv[i], "-ip") == 0)
  418. {
  419. i++;
  420. ipAddr.append(argv[i++]);
  421. if (strcmp(ipAddr, ".")!=0)
  422. {
  423. IpAddress ip(ipAddr.str());
  424. ipAddr.clear();
  425. if (ip.isLoopBack()) // assume they meant any local ip... not sure this is a good idea
  426. ipAddr.append('.');
  427. else
  428. ip.getIpText(ipAddr);
  429. }
  430. }
  431. else if(stricmp(argv[i], "-od") == 0)
  432. {
  433. i++;
  434. out_dirname = argv[i++];
  435. }
  436. else if(stricmp(argv[i], "-id") == 0)
  437. {
  438. i++;
  439. in_dirname = argv[i++];
  440. }
  441. else if (stricmp(argv[i], "-list") == 0)
  442. {
  443. i++;
  444. listComps = true;
  445. }
  446. else if (stricmp(argv[i], "-listall") == 0)
  447. {
  448. i++;
  449. listallComps = true;
  450. }
  451. else if (stricmp(argv[i], "-listdirs") == 0)
  452. {
  453. i++;
  454. listdirs = true;
  455. }
  456. else if (stricmp(argv[i], "-listdropzones") == 0)
  457. {
  458. i++;
  459. listdropzones = true;
  460. }
  461. else if (stricmp(argv[i], "-listcommondirs") == 0)
  462. {
  463. i++;
  464. listcommondirs = true;
  465. }
  466. else if (stricmp(argv[i], "-machines") == 0)
  467. {
  468. i++;
  469. listMachines = true;
  470. }
  471. else if (stricmp(argv[i], "-validateonly") == 0)
  472. {
  473. i++;
  474. validateOnly = true;
  475. }
  476. else if (stricmp(argv[i], "-v") == 0)
  477. {
  478. i++;
  479. verbose = true;
  480. }
  481. else
  482. {
  483. fprintf(stderr, "Error: unknown command line parameter: %s\n", argv[i]);
  484. usage();
  485. releaseAtoms();
  486. return 1;
  487. }
  488. }
  489. if (!in_cfgname)
  490. {
  491. fprintf(stderr, "Error: Environment xml file is required. Please specify.\n");
  492. usage();
  493. releaseAtoms();
  494. return 1;
  495. }
  496. if (ipAddr.length() == 0 && !listallComps && !validateOnly && !listcommondirs && !listMachines)
  497. ipAddr.clear().append("."); // Meaning match any local address
  498. try
  499. {
  500. processRequest(in_cfgname, out_dirname, in_dirname, compName,
  501. compType,in_filename, out_filename, generateOutput, ipAddr.length() ? ipAddr.str(): NULL,
  502. listComps, verbose, listallComps, listdirs, listdropzones, listcommondirs, listMachines, validateOnly);
  503. }
  504. catch(IException *excpt)
  505. {
  506. StringBuffer errMsg;
  507. fprintf(stderr, "Exception: %d:\n%s\n", excpt->errorCode(), excpt->errorMessage(errMsg).str());
  508. releaseAtoms();
  509. excpt->Release();
  510. return 1;
  511. }
  512. catch(...)
  513. {
  514. fprintf(stderr, "Unknown exception\n");
  515. releaseAtoms();
  516. return 1;
  517. }
  518. releaseAtoms();
  519. return 0;
  520. }