main.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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(), "ThorSlaveProcess") || !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. netAddr.clear().append(pInst->queryProp("@netAddress"));
  346. port.clear().append(pInst->queryProp("@port"));
  347. if (multiInstances)
  348. processName.clear().append(pInst->queryName());
  349. out.appendf("%s,%s,%s,%s,%s%c%s,%s\n", processName.str(),
  350. pComponent->queryProp("@name"), netAddr.str(), port.str(),
  351. STANDARD_OUTDIR, PATHSEPCHAR, pComponent->queryProp("@name"), pComponent->queryProp("@logDir"));
  352. }
  353. }
  354. else
  355. {
  356. netAddr.clear().append(pComponent->queryProp("@netAddress"));
  357. port.clear().append(pComponent->queryProp("@port"));
  358. out.appendf("%s,%s,%s,%s,%s%c%s,%s\n", pComponent->queryName(),
  359. pComponent->queryProp("@name"), netAddr.str(), port.str(),
  360. STANDARD_OUTDIR, PATHSEPCHAR, pComponent->queryProp("@name"), pComponent->queryProp("@logDir"));
  361. }
  362. }
  363. }
  364. fprintf(stdout, "%s", out.str());
  365. }
  366. return 0;
  367. }
  368. int main(int argc, char** argv)
  369. {
  370. InitModuleObjects();
  371. Owned<IProperties> globals = createProperties(true);
  372. const char* in_filename = NULL;
  373. const char* in_cfgname = NULL;
  374. const char* out_dirname = STANDARD_OUTDIR;
  375. const char* in_dirname = STANDARD_INDIR;
  376. const char* out_filename = NULL;
  377. const char* compName = NULL;
  378. const char* compType = NULL;
  379. StringBuffer ipAddr = NULL;
  380. bool generateOutput = true;
  381. bool listComps = false;
  382. bool verbose = false;
  383. bool listallComps = false;
  384. bool listdirs = false;
  385. bool listdropzones = false;
  386. bool listcommondirs = false;
  387. bool listMachines = false;
  388. bool validateOnly = false;
  389. int i = 1;
  390. bool writeToFiles = false;
  391. int port = 80;
  392. while(i<argc)
  393. {
  394. if(stricmp(argv[i], "-help") == 0 || stricmp(argv[i], "-?") == 0)
  395. {
  396. usage();
  397. releaseAtoms();
  398. return 0;
  399. }
  400. else if (stricmp(argv[i], "-env") == 0)
  401. {
  402. i++;
  403. in_cfgname = argv[i++];
  404. }
  405. else if (stricmp(argv[i], "-c") == 0)
  406. {
  407. i++;
  408. compName = argv[i++];
  409. }
  410. else if (stricmp(argv[i], "-t") == 0)
  411. {
  412. i++;
  413. compType = argv[i++];
  414. }
  415. else if (stricmp(argv[i], "-ip") == 0)
  416. {
  417. i++;
  418. ipAddr.append(argv[i++]);
  419. if (strcmp(ipAddr, ".")!=0)
  420. {
  421. IpAddress ip(ipAddr.str());
  422. ipAddr.clear();
  423. if (ip.isLoopBack()) // assume they meant any local ip... not sure this is a good idea
  424. ipAddr.append('.');
  425. else
  426. ip.getIpText(ipAddr);
  427. }
  428. }
  429. else if(stricmp(argv[i], "-od") == 0)
  430. {
  431. i++;
  432. out_dirname = argv[i++];
  433. }
  434. else if(stricmp(argv[i], "-id") == 0)
  435. {
  436. i++;
  437. in_dirname = argv[i++];
  438. }
  439. else if (stricmp(argv[i], "-list") == 0)
  440. {
  441. i++;
  442. listComps = true;
  443. }
  444. else if (stricmp(argv[i], "-listall") == 0)
  445. {
  446. i++;
  447. listallComps = true;
  448. }
  449. else if (stricmp(argv[i], "-listdirs") == 0)
  450. {
  451. i++;
  452. listdirs = true;
  453. }
  454. else if (stricmp(argv[i], "-listdropzones") == 0)
  455. {
  456. i++;
  457. listdropzones = true;
  458. }
  459. else if (stricmp(argv[i], "-listcommondirs") == 0)
  460. {
  461. i++;
  462. listcommondirs = true;
  463. }
  464. else if (stricmp(argv[i], "-machines") == 0)
  465. {
  466. i++;
  467. listMachines = true;
  468. }
  469. else if (stricmp(argv[i], "-validateonly") == 0)
  470. {
  471. i++;
  472. validateOnly = true;
  473. }
  474. else if (stricmp(argv[i], "-v") == 0)
  475. {
  476. i++;
  477. verbose = true;
  478. }
  479. else
  480. {
  481. fprintf(stderr, "Error: unknown command line parameter: %s\n", argv[i]);
  482. usage();
  483. releaseAtoms();
  484. return 1;
  485. }
  486. }
  487. if (!in_cfgname)
  488. {
  489. fprintf(stderr, "Error: Environment xml file is required. Please specify.\n");
  490. usage();
  491. releaseAtoms();
  492. return 1;
  493. }
  494. if (ipAddr.length() == 0 && !listallComps && !validateOnly && !listcommondirs && !listMachines)
  495. ipAddr.clear().append("."); // Meaning match any local address
  496. try
  497. {
  498. processRequest(in_cfgname, out_dirname, in_dirname, compName,
  499. compType,in_filename, out_filename, generateOutput, ipAddr.length() ? ipAddr.str(): NULL,
  500. listComps, verbose, listallComps, listdirs, listdropzones, listcommondirs, listMachines, validateOnly);
  501. }
  502. catch(IException *excpt)
  503. {
  504. StringBuffer errMsg;
  505. fprintf(stderr, "Exception: %d:\n%s\n", excpt->errorCode(), excpt->errorMessage(errMsg).str());
  506. releaseAtoms();
  507. excpt->Release();
  508. return 1;
  509. }
  510. catch(...)
  511. {
  512. fprintf(stderr, "Unknown exception\n");
  513. releaseAtoms();
  514. return 1;
  515. }
  516. releaseAtoms();
  517. return 0;
  518. }