EnvGen.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <map>
  14. #include <string>
  15. #include "XMLTags.h"
  16. #include "jliball.hpp"
  17. #include "EnvGen.hpp"
  18. map<string, string> CEnvGen::m_envCategoryMap =
  19. {
  20. {"" , "Software"},
  21. {"sw", "Software"},
  22. {"pg", "Programs"},
  23. {"es", "EnvSettings"},
  24. {"hd", "Hardware"}
  25. };
  26. map<string, string> CEnvGen::m_actionAbbrMap =
  27. {
  28. {"add" , "add"},
  29. {"modify", "mod"},
  30. {"remove", "rmv"}
  31. };
  32. CEnvGen::CEnvGen()
  33. {
  34. m_showInputOnly = false;
  35. m_inputFormat = XML_Format;
  36. m_displayFormat = XML_Format;
  37. m_iConfigEnv = NULL;
  38. }
  39. CEnvGen::~CEnvGen()
  40. {
  41. if (m_iConfigEnv) ConfigEnvFactory::destroy(m_iConfigEnv);
  42. }
  43. bool CEnvGen::parseArgs(int argc, char** argv)
  44. {
  45. int i = 1;
  46. //m_params = createPTree("Env");
  47. m_params.setown(createPTree("Env"));
  48. IPropertyTree * config = createPTree("Config");
  49. m_params->addPropTree("Config", config);
  50. while (i < argc)
  51. {
  52. if (stricmp(argv[i], "-help") == 0 || stricmp(argv[i], "-?") == 0)
  53. {
  54. usage();
  55. return false;
  56. }
  57. else if (stricmp(argv[i], "-mode") == 0)
  58. {
  59. i++;
  60. config->setProp("@mode", argv[i++]);
  61. }
  62. else if ((stricmp(argv[i], "-env") == 0) || (stricmp(argv[i], "-env-out") == 0))
  63. {
  64. i++;
  65. config->addProp("@env-out", argv[i++]);
  66. }
  67. else if (stricmp(argv[i], "-env-in") == 0)
  68. {
  69. i++;
  70. config->addProp("@env-in", argv[i++]);
  71. }
  72. else if (stricmp(argv[i], "-ip") == 0)
  73. {
  74. i++;
  75. config->addProp("@ip-list", argv[i++]);
  76. }
  77. else if (stricmp(argv[i], "-ipfile") == 0)
  78. {
  79. i++;
  80. config->addProp("@ip-file", argv[i++]);
  81. }
  82. else if (stricmp(argv[i], "-supportnodes") == 0)
  83. {
  84. i++;
  85. config->addProp("@support-nodes", argv[i++]);
  86. }
  87. else if (stricmp(argv[i], "-espnodes") == 0)
  88. {
  89. i++;
  90. config->addProp("@esp-nodes", argv[i++]);
  91. }
  92. else if (stricmp(argv[i], "-roxienodes") == 0)
  93. {
  94. i++;
  95. config->addProp("@roxie-nodes", argv[i++]);
  96. }
  97. else if (stricmp(argv[i], "-thornodes") == 0)
  98. {
  99. i++;
  100. config->addProp("@thor-nodes", argv[i++]);
  101. }
  102. else if (stricmp(argv[i], "-slavespernode") == 0)
  103. {
  104. i++;
  105. config->addProp("@slaves-per-node", argv[i++]);
  106. }
  107. else if (stricmp(argv[i], "-thorchannelsperslave") == 0)
  108. {
  109. i++;
  110. config->addProp("@thor-channels-per-slave", argv[i++]);
  111. }
  112. else if (stricmp(argv[i], "-roxiechannelsperslave") == 0)
  113. {
  114. i++;
  115. config->addProp("@roxie-channels-per-slave", argv[i++]);
  116. }
  117. else if (stricmp(argv[i], "-roxieondemand") == 0)
  118. {
  119. i++;
  120. if (!strcmp(argv[i++], "0"))
  121. config->addProp("@roxie-on-demand", "false");
  122. }
  123. else if (stricmp(argv[i], "-o") == 0)
  124. {
  125. i++;
  126. StringArray sbarr;
  127. sbarr.appendList(argv[i++], "=");
  128. if (sbarr.length() != 2)
  129. continue;
  130. if (strstr(sbarr.item(1), "[NAME]") && (strstr(sbarr.item(1), "[INST]") || strstr(sbarr.item(1), "[COMPONENT]")))
  131. {
  132. StringBuffer sb;
  133. sb.clear().appendf("sw:dirs:category@%s=%s",sbarr.item(0), sbarr.item(1));
  134. createUpdateTask("modify", config, sb.str());
  135. }
  136. else
  137. {
  138. fprintf(stderr, "Error: Directory Override must contain [NAME] and either [INST] or [COMPONENT]\n");
  139. return false;
  140. }
  141. }
  142. else if (stricmp(argv[i], "-override") == 0)
  143. {
  144. i++;
  145. if (!convertOverrideTask(config, argv[i++]))
  146. return false;
  147. }
  148. else if (stricmp(argv[i], "-set-xpath-attrib-value")== 0)
  149. {
  150. i++;
  151. m_arrXPaths.append(*new StringBufferItem (argv[i++]));
  152. m_arrAttrib.append(*new StringBufferItem (argv[i++]));
  153. m_arrValues.append(*new StringBufferItem (argv[i++]));
  154. }
  155. // new parameters
  156. else if (stricmp(argv[i], "-env-options") == 0)
  157. {
  158. i++;
  159. config->addProp("@options", argv[i++]);
  160. }
  161. else if (stricmp(argv[i], "-env-rules") == 0)
  162. {
  163. i++;
  164. config->addProp("@rules", argv[i++]);
  165. }
  166. else if (stricmp(argv[i], "-buildset") == 0)
  167. {
  168. i++;
  169. config->addProp("@buildset", argv[i++]);
  170. }
  171. else if (stricmp(argv[i], "-add") == 0)
  172. {
  173. i++;
  174. createUpdateTask("add", config, argv[i++]);
  175. }
  176. else if (stricmp(argv[i], "-mod") == 0)
  177. {
  178. i++;
  179. createUpdateTask("modify", config, argv[i++]);
  180. }
  181. else if (stricmp(argv[i], "-rmv") == 0)
  182. {
  183. i++;
  184. createUpdateTask("remove", config, argv[i++]);
  185. }
  186. else if (stricmp(argv[i], "-add-node") == 0)
  187. {
  188. i++;
  189. createUpdateNodeTask("add", config, argv[i++]);
  190. }
  191. else if (stricmp(argv[i], "-mod-node") == 0)
  192. {
  193. i++;
  194. createUpdateNodeTask("modify", config, argv[i++]);
  195. }
  196. else if (stricmp(argv[i], "-rmv-node") == 0)
  197. {
  198. i++;
  199. createUpdateNodeTask("remove", config, argv[i++]);
  200. }
  201. else if (stricmp(argv[i], "-add-binding") == 0)
  202. {
  203. i++;
  204. createUpdateBindingTask("add", config, argv[i++]);
  205. }
  206. else if (stricmp(argv[i], "-mod-binding") == 0)
  207. {
  208. i++;
  209. createUpdateBindingTask("modify", config, argv[i++]);
  210. }
  211. else if (stricmp(argv[i], "-rmv-binding") == 0)
  212. {
  213. i++;
  214. createUpdateBindingTask("remove", config, argv[i++]);
  215. }
  216. else if (stricmp(argv[i], "-add-service") == 0)
  217. {
  218. i++;
  219. createUpdateServiceTask("add", config, argv[i++]);
  220. }
  221. else if (stricmp(argv[i], "-mod-service") == 0)
  222. {
  223. i++;
  224. createUpdateServiceTask("modify", config, argv[i++]);
  225. }
  226. else if (stricmp(argv[i], "-rmv-service") == 0)
  227. {
  228. i++;
  229. createUpdateServiceTask("remove", config, argv[i++]);
  230. }
  231. else if (stricmp(argv[i], "-add-topology") == 0)
  232. {
  233. i++;
  234. createUpdateTopologyTask("add", config, argv[i++]);
  235. }
  236. else if (stricmp(argv[i], "-mod-topology") == 0)
  237. {
  238. i++;
  239. createUpdateTopologyTask("modify", config, argv[i++]);
  240. }
  241. else if (stricmp(argv[i], "-rmv-topology") == 0)
  242. {
  243. i++;
  244. createUpdateTopologyTask("remove", config, argv[i++]);
  245. }
  246. else if (stricmp(argv[i], "-in-file") == 0)
  247. {
  248. i++;
  249. addUpdateTaskFromFile(argv[i++]);
  250. }
  251. else if (stricmp(argv[i], "-add-content")== 0)
  252. {
  253. i++;
  254. m_arrContentXPaths.append(*new StringBufferItem (argv[i++]));
  255. const char* fileName = argv[i++];
  256. StringBufferItem * sbi = new StringBufferItem() ;
  257. sbi->loadFile(fileName);
  258. m_arrContents.append(*sbi);
  259. if ((String(fileName).toLowerCase())->endsWith(".json"))
  260. m_arrContentFormats.append(*new StringBufferItem("json"));
  261. else
  262. m_arrContentFormats.append(*new StringBufferItem("xml"));
  263. }
  264. else if (stricmp(argv[i], "-show-input-only") == 0)
  265. {
  266. i++;
  267. m_showInputOnly = true;
  268. m_displayFormat = XML_Format;
  269. }
  270. else if (stricmp(argv[i], "-show-input-json-only") == 0)
  271. {
  272. i++;
  273. m_showInputOnly = true;
  274. m_displayFormat = JSON_Format;
  275. }
  276. else if (stricmp(argv[i], "-help-update-1") == 0)
  277. {
  278. usage_update_input_format_1();
  279. return false;
  280. }
  281. else if (stricmp(argv[i], "-help-update-2") == 0)
  282. {
  283. usage_update_input_format_2();
  284. return false;
  285. }
  286. else if (stricmp(argv[i], "-help-update-3") == 0)
  287. {
  288. usage_update_input_format_3();
  289. return false;
  290. }
  291. else if (stricmp(argv[i], "-help-update-3-json") == 0)
  292. {
  293. usage_update_input_format_3_json();
  294. return false;
  295. }
  296. else if (stricmp(argv[i], "-cloud") == 0)
  297. {
  298. i++;
  299. cloudConfiguration(config, argv[i++]);
  300. }
  301. else
  302. {
  303. fprintf(stderr, "\nUnknown option %s\n", argv[i]);
  304. usage();
  305. return false;
  306. }
  307. }
  308. // Check input parameters
  309. if (!config->queryProp("@env-out"))
  310. {
  311. fprintf(stderr, "\nMissing -env-out\n");
  312. usage();
  313. return false;
  314. }
  315. if (!config->queryProp("@mode"))
  316. {
  317. if (config->queryProp("@env-in"))
  318. config->addProp("@mode", "update");
  319. else
  320. config->addProp("@mode", "create");
  321. }
  322. if (!stricmp(config->queryProp("@mode"), "update") &&
  323. !config->queryProp("@env-in"))
  324. {
  325. fprintf(stderr, "\nMissing input enviroment.xml (-env-in) in update mode\n");
  326. return false;
  327. }
  328. if (!stricmp(config->queryProp("@mode"), "create") &&
  329. !config->hasProp("@ip-list") && !config->hasProp("@ip-file"))
  330. {
  331. config->setProp("@support-nodes", "0");
  332. config->setProp("@roxie-nodes", "0");
  333. config->setProp("@thor-nodes", "0");
  334. config->setProp("@esp-nodes", "0");
  335. }
  336. m_iConfigEnv = ConfigEnvFactory::getIConfigEnv(config);
  337. return true;
  338. }
  339. void CEnvGen::createUpdateTask(const char* action, IPropertyTree * config, const char* param)
  340. {
  341. if (!param || !(*param)) return;
  342. if (m_showInputOnly)
  343. {
  344. printf("Input as one line format: -%s %s\n", (m_actionAbbrMap.at(action)).c_str(), param);
  345. }
  346. StringArray items;
  347. items.appendList(param, ":");
  348. if (items.ordinality() < 2)
  349. {
  350. throw MakeStringException(CfgEnvErrorCode::InvalidParams,
  351. "Incorrect input format. At least two item expected: category:component.\n See usage for deail.");
  352. }
  353. IPropertyTree * updateTree = createPTree("Task");
  354. config->addPropTree("Task", updateTree);
  355. updateTree->addProp("@operation", action);
  356. updateTree->addProp("@category", (m_envCategoryMap.at(items.item(0))).c_str());
  357. //have key and attributes
  358. StringArray compAndAttrs;
  359. compAndAttrs.appendList(items.item(1), "@");
  360. StringArray compAndTarget;
  361. compAndTarget.appendList(compAndAttrs[0], "%");
  362. if (!stricmp(action, "remove") && compAndTarget.ordinality() > 1 )
  363. {
  364. if (*(compAndTarget.item(1))) updateTree->addProp("@target", compAndTarget.item(1));
  365. }
  366. StringArray compAndKey;
  367. compAndKey.appendList(compAndTarget.item(0), "#");
  368. updateTree->addProp("@component", compAndKey.item(0));
  369. if (compAndKey.ordinality() > 1)
  370. {
  371. StringArray keyAndClone;
  372. keyAndClone.appendList(compAndKey.item(1), ATTR_V_SEP);
  373. updateTree->addProp("@key", keyAndClone.item(0));
  374. if (keyAndClone.ordinality() > 1)
  375. updateTree->addProp("@clone", keyAndClone.item(1));
  376. }
  377. if (compAndAttrs.ordinality() > 1)
  378. {
  379. addUpdateAttributesFromString(updateTree, compAndAttrs.item(1));
  380. return;
  381. }
  382. if (items.ordinality() == 2)
  383. return;
  384. int index = 2;
  385. // selector
  386. StringArray selectorAndAttrs;
  387. selectorAndAttrs.appendList(items.item(index), "@");
  388. StringArray selectorParts;
  389. selectorParts.appendList(selectorAndAttrs.item(0), "/");
  390. StringBuffer sbSelector;
  391. for ( unsigned i = 0; i < selectorParts.ordinality()-1 ; i++)
  392. {
  393. if (!sbSelector.isEmpty())
  394. sbSelector.append("/");
  395. sbSelector.append(selectorParts.item(i));
  396. }
  397. StringArray selectorAndKey;
  398. selectorAndKey.appendList(selectorParts.item(selectorParts.ordinality()-1), "#");
  399. if (!sbSelector.isEmpty())
  400. sbSelector.append("/");
  401. sbSelector.append(selectorAndKey.item(0));
  402. sbSelector.replace('#', '@');
  403. updateTree->addProp("@selector", sbSelector.str());
  404. if (selectorAndKey.ordinality() > 1)
  405. updateTree->addProp("@selector-key", selectorAndKey.item(1));
  406. if (selectorAndAttrs.ordinality() > 1)
  407. {
  408. addUpdateAttributesFromString(updateTree, selectorAndAttrs.item(1));
  409. }
  410. index++;
  411. if (items.ordinality() == index) return;
  412. // children nodes
  413. IPropertyTree *children = updateTree->addPropTree("Children", createPTree("Children"));
  414. for ( unsigned i = index; i < items.ordinality() ; i++)
  415. {
  416. IPropertyTree *child = children->addPropTree("Child", createPTree("Child"));
  417. StringArray nameAndAttrs;
  418. nameAndAttrs.appendList(items.item(i), "@");
  419. child->addProp("@name", nameAndAttrs.item(0));
  420. if (nameAndAttrs.ordinality() > 1)
  421. addUpdateAttributesFromString(child, nameAndAttrs.item(1));
  422. }
  423. }
  424. void CEnvGen::addUpdateAttributesFromString(IPropertyTree *updateTree, const char *attrs)
  425. {
  426. StringArray saAttrs;
  427. saAttrs.appendList(attrs, ATTR_SEP);
  428. //printf("attribute: %s\n",attrs);
  429. IPropertyTree *pAttrs = updateTree->addPropTree("Attributes", createPTree("Attributes"));
  430. for ( unsigned i = 0; i < saAttrs.ordinality() ; i++)
  431. {
  432. IPropertyTree *pAttr = pAttrs->addPropTree("Attribute", createPTree("Attribute"));
  433. StringArray keyValues;
  434. keyValues.appendList(saAttrs[i], "=");
  435. pAttr->addProp("@name", keyValues[0]);
  436. StringBuffer sbValue;
  437. sbValue.clear().appendf("%s", keyValues[1]);
  438. sbValue.replaceString("[equal]", "=");
  439. StringArray newOldValues;
  440. if (strcmp(keyValues[1], "") != 0)
  441. {
  442. newOldValues.appendList(sbValue.str(), ATTR_V_SEP);
  443. pAttr->addProp("@value", newOldValues[0]);
  444. if (newOldValues.ordinality() > 1) pAttr->addProp("@oldValue", newOldValues[1]);
  445. }
  446. else
  447. pAttr->addProp("@value", "");
  448. }
  449. }
  450. void CEnvGen::createUpdateNodeTask(const char* action, IPropertyTree * config, const char* param)
  451. {
  452. StringBuffer sbParam;
  453. StringArray parts;
  454. parts.appendList(param, ":");
  455. String part1(parts.item(0));
  456. if (part1.startsWith("spark"))
  457. {
  458. sbParam.clear().append("pg:buildset#sparkthor");
  459. createUpdateTask(action, config, sbParam.str());
  460. }
  461. if (part1.startsWith("thor"))
  462. {
  463. for ( unsigned i = 1; i < parts.ordinality() ; i++)
  464. {
  465. sbParam.clear().append("sw:");
  466. StringBuffer sbPart1(part1.str());
  467. sbPart1.append(":instance-").appendf("%s",parts.item(i));
  468. sbParam.appendf("%s", sbPart1.str());
  469. createUpdateTask(action, config, sbParam.str());
  470. }
  471. }
  472. else
  473. {
  474. if (part1.startsWith("computer"))
  475. sbParam.append("hd:").appendf("%s", part1.str());
  476. else
  477. {
  478. sbParam.clear().append("sw:");
  479. StringBuffer sbPart1(part1.str());
  480. sbPart1.replaceString("@", ":instance@");
  481. sbParam.appendf("%s", sbPart1.str());
  482. }
  483. createUpdateTask(action, config, sbParam.str());
  484. }
  485. }
  486. void CEnvGen::createUpdateBindingTask(const char* action, IPropertyTree * config, const char* param)
  487. {
  488. StringArray bindingAndAttrs;
  489. bindingAndAttrs.appendList(param, "@");
  490. StringArray espAndBinding;
  491. espAndBinding.appendList(bindingAndAttrs.item(0), ":");
  492. if (bindingAndAttrs.ordinality() != 2)
  493. {
  494. if (!stricmp(action, "modify") && (espAndBinding.ordinality() != 2))
  495. throw MakeStringException(CfgEnvErrorCode::InvalidParams,
  496. "\"-mod-binding\" should have format: <esp name>:<binding name>@attr1=<value>^attr2=value>");
  497. else if (!stricmp(action, "add"))
  498. throw MakeStringException(CfgEnvErrorCode::InvalidParams,
  499. "\"-add-binding\" should have format: <esp name>@name=<value>^service=<value>");
  500. }
  501. if (!stricmp(action, "remove") && (espAndBinding.ordinality() != 2))
  502. throw MakeStringException(CfgEnvErrorCode::InvalidParams,
  503. "\"-rmv-binding\" should have format: <esp name>:<binding name>");
  504. StringBuffer sbParam;
  505. sbParam.appendf("sw:esp#%s:EspBinding", espAndBinding.item(0));
  506. if ((espAndBinding.ordinality() == 2) && *(espAndBinding.item(1)))
  507. {
  508. if (stricmp(action, "remove"))
  509. sbParam.appendf("#%s", espAndBinding.item(1));
  510. else
  511. sbParam.appendf("@name=%s", espAndBinding.item(1));
  512. }
  513. if (stricmp(action, "remove"))
  514. sbParam.appendf("@%s", bindingAndAttrs.item(1));
  515. createUpdateTask(action, config, sbParam.str());
  516. }
  517. void CEnvGen::createUpdateServiceTask(const char* action, IPropertyTree * config, const char* param)
  518. {
  519. StringBuffer sbParam;
  520. sbParam.append("sw:").appendf("%s", param);
  521. createUpdateTask(action, config, sbParam.str());
  522. }
  523. void CEnvGen::createUpdateTopologyTask(const char* action, IPropertyTree * config, const char* param)
  524. {
  525. StringBuffer sbParam;
  526. if (!stricmp(action, "add") && !stricmp(param, "default"))
  527. {
  528. sbParam.clear().append("sw:topology#topology:cluster@name=thor:eclagent@process=myeclagent:eclscheduler@process=myeclscheduler:eclccserver@process=myeclccserver:thor@process=mythor");
  529. createUpdateTask(action, config, sbParam.str());
  530. sbParam.clear().append("sw:topology#topology:cluster@name=roxie:eclscheduler@process=myeclscheduler:eclccserver@process=myeclccserver:roxie@process=myroxie");
  531. createUpdateTask(action, config, sbParam.str());
  532. sbParam.clear().append("sw:topology#topology:cluster@name=thor_roxie:eclscheduler@process=myeclscheduler:eclccserver@process=myeclccserver:roxie@process=myroxie:thor@process=mythor");
  533. createUpdateTask(action, config, sbParam.str());
  534. }
  535. else
  536. {
  537. sbParam.clear().append("sw:topology#").appendf("%s", param);
  538. createUpdateTask(action, config, sbParam.str());
  539. }
  540. }
  541. bool CEnvGen::process()
  542. {
  543. if (m_showInputOnly)
  544. {
  545. if (m_displayFormat == XML_Format)
  546. {
  547. StringBuffer cfgXML;
  548. toXML(m_params, cfgXML.clear());
  549. printf("Input as XML format:\n");
  550. printf("%s\n\n",cfgXML.str());
  551. }
  552. else if (m_displayFormat == JSON_Format)
  553. {
  554. StringBuffer cfgJSON;
  555. toJSON(m_params, cfgJSON.clear());
  556. printf("Input as JSON format:\n");
  557. printf("%s\n\n",cfgJSON.str());
  558. }
  559. else
  560. printf("Unknown display format: %d \n\n", m_displayFormat);
  561. return true;
  562. }
  563. IPropertyTree* config = m_params->queryPropTree("Config");
  564. const char* mode = config->queryProp("@mode");
  565. if (!stricmp(mode, "create") )
  566. m_iConfigEnv->create(config);
  567. else
  568. m_iConfigEnv->runUpdateTasks(config);
  569. // blindly set attribute with xpath
  570. if (m_arrXPaths.length() > 0)
  571. {
  572. unsigned nCount = 0;
  573. while (nCount < m_arrXPaths.length())
  574. {
  575. m_iConfigEnv->setAttribute( m_arrXPaths.item(nCount).str(),
  576. m_arrAttrib.item(nCount).str(),
  577. m_arrValues.item(nCount).str()
  578. );
  579. nCount++;
  580. }
  581. }
  582. // blindly add content with xpath
  583. if (m_arrContentXPaths.length() > 0)
  584. {
  585. unsigned nCount = 0;
  586. while (nCount < m_arrContentXPaths.length())
  587. {
  588. int format = (!stricmp(m_arrContentFormats.item(nCount), "json")) ? JSON_Format : XML_Format;
  589. m_iConfigEnv->addContent( m_arrContentXPaths.item(nCount),
  590. m_arrContents.item(nCount), format);
  591. nCount++;
  592. }
  593. }
  594. StringBuffer out;
  595. m_iConfigEnv->getContent(NULL, out, XML_SortTags | XML_Format);
  596. Owned<IFile> pFile;
  597. const char* envFile = config->queryProp("@env-out");
  598. //printf("output envxml to file %s\n", envFile);
  599. pFile.setown(createIFile(envFile));
  600. Owned<IFileIO> pFileIO;
  601. pFileIO.setown(pFile->open(IFOcreaterw));
  602. pFileIO->write(0, out.length(), out.str());
  603. //printf("%s", out.str());
  604. if (!m_iConfigEnv->isEnvironmentValid(out))
  605. {
  606. fprintf(stderr, "The result environment.xml is invalid.\n");
  607. return false;
  608. }
  609. return true;
  610. }
  611. void CEnvGen::usage()
  612. {
  613. const char* version = "0.1";
  614. printf("\nHPCC Systems® environment generator. version %s. Usage:\n", version);
  615. puts(" envgen2 -env-out <environment file> -ip <ip addr> [options]");
  616. puts("");
  617. puts("options: ");
  618. puts(" -env-in : Full path of the input environment file to update.");
  619. puts(" -env-out | -env: Full path of the output environment file to generate or update.");
  620. puts(" If a file with the same name exists, and no \"-update\" provided");
  621. puts(" a new name with _xxx will be generated ");
  622. puts(" -ip : Ip addresses that should be used for environment generation");
  623. puts(" Allowed formats are ");
  624. puts(" X.X.X.X;");
  625. puts(" X.X.X.X-XXX;");
  626. puts(" -ipfile: name of the file that contains Ip addresses");
  627. puts(" Allowed formats are ");
  628. puts(" X.X.X.X;");
  629. puts(" X.X.X.X-XXX;");
  630. puts(" -supportnodes <number of support nodes>: Number of nodes to be used");
  631. puts(" for non-Thor and non-Roxie components. If not specified or ");
  632. puts(" specified as 0, Thor and Roxie nodes may overlap with support");
  633. puts(" nodes. If an invalid value is provided, support nodes are ");
  634. puts(" treated as 0");
  635. puts(" -roxienodes <number of roxie nodes>: Number of nodes to be generated ");
  636. puts(" for Roxie. If not specified or specified as 0, no roxie nodes");
  637. puts(" are generated");
  638. puts(" -thornodes <number of thor nodes>: Number of nodes to be generated ");
  639. puts(" for Thor slaves. A node for thor master is automatically added. ");
  640. puts(" If not specified or specified as 0, no thor nodes");
  641. puts(" -espnodes <number of esp nodes>: Number of nodes to be generated ");
  642. puts(" If not specified a single ESP node is generated");
  643. puts(" If 0 is specified then all available nodes specified with assign_ips flag ");
  644. puts(" will be used, otherwise 0 ESP nodes will be generated.");
  645. puts(" -slavesPerNode <number of thor slaves per node>: Number of thor nodes ");
  646. puts(" per slave.");
  647. puts(" -thorChannelsPerSlave <number of channels per thor slave>: Number of thor channels per slave.");
  648. puts(" The default is 1.");
  649. puts(" -roxieChannelsPerSlave <number of channels per roxie slave>: Number of roxie channels per slave.");
  650. puts(" The default is 1.");
  651. puts(" -roxieondemand <enable roxie on demand(1) or disable roxie on demand(any ");
  652. puts(" other value)>: Specify 1 to enable Roxie on demand. ");
  653. puts(" Any other value will disable Roxie on demand");
  654. puts(" -o <categoryname=newdirvalue>: overrides for any common directories");
  655. puts(" There can be multiple -o options. Each override should still");
  656. puts(" contain a [NAME] and either a [CATEGORY] or [INST]. ");
  657. puts(" If a category already exists, the directory value is updated. Otherwise");
  658. puts(" a new category is created.");
  659. puts(" For example, \"-o log=/var/logs/[NAME]/mylogs/[INST] -o run=/var/run/[NAME]/myrun/[INST]\"");
  660. puts(" -override <buildset,xpath,value>: overrides all component properties with the");
  661. puts(" given xpath for the given buildset with the value provided. If the xpath is");
  662. puts(" not already present, it is added to any of the components");
  663. puts(" There can be multiple of the -override options. For example, to override the dropzone");
  664. puts(" directory and to set eclwatch's enableSystemUseRewrite to true, provide the following options:");
  665. puts(" \"-override DropZone,@directory,/mnt/disk1/mydropzone ");
  666. puts(" -override espsmc,@enableSystemUseRewrite,true\"");
  667. puts(" -set-xpath-attrib-value <XPATH> <ATTRIBUTE> <VALUE>: sets or add the xpath attribute and value.");
  668. puts(" Example: \"-set-xpath-attrib-value Software/Topology/Cluster[@name=\"thor\"]/ThorCluster @process thor123\"");
  669. puts(" -add-content <XPATH> <content file in XML or JSON format>: adds content to the xpath.");
  670. puts(" Example: \"-add-content Software/Topology /tmp/new_topology_cluster.xml");
  671. puts(" -env-options environment options file. The default is /etc/HPCCSystems/environment.conf.");
  672. puts(" -env-rules: a rule file to generate environment. The default is /etc/HPCCSystems/genenvrules.conf.");
  673. puts(" -env-rules: a rule file to generate environment. The default is /etc/HPCCSystems/genenvrules.conf.");
  674. puts(" -buildset: the buildset file with full path. The directory also contains all XSD files.");
  675. puts(" the default is /opt/HPCCSystems/componentfiles/configxml/buildset.xml.");
  676. puts(" -cloud <none|aws>: set certain attributes for particular cloud environment. The default is none");
  677. puts("");
  678. puts("For update, there are three input formats. See following for the usage.");
  679. puts(" -help-update-1: show common update options");
  680. puts(" -help-update-2 (for internal use): show more general one-line update options");
  681. puts(" -help-update-3 (for internal use): show update options in xml format");
  682. puts(" -help-update-3-json (for internal use): show update options in json format");
  683. puts("");
  684. puts(" -show-input-only: show input parameters in xml format. Doesn't create/update environment.");
  685. puts(" -show-input-json-only: show input parameters in json format. Doesn't create/update environment.");
  686. puts(" -help: print out this usage.");
  687. puts("");
  688. }
  689. void CEnvGen::usage_update_input_format_1()
  690. {
  691. //new options
  692. puts("");
  693. puts("These options are for basic environment operations.");
  694. puts(" -add-node comp#name@(ip|ipfile)=<value> for ip <value> can be <value1>;<value2>...");
  695. puts(" -mod-node \"comp#name@ip=<new>\\|<old>\"");
  696. puts(" -rmv-node comp#name@ip=<value>");
  697. puts("For examples:");
  698. puts(" -add-node thor#name:master@ip=10.20.10.10:slave@ipfile=/tmp/slave_ip_list");
  699. puts(" -mod-node \"thor#name:master@ip=1.10.12.8\\|1.20.10.10\"");
  700. puts(" -rmv-node \"thor#name:slave@ip=10.20.2.10\\|10.20.12.2\"");
  701. puts(" -add-node \"roxie#newroxie\\|myroxie@ip=1.20.20.10-11");
  702. puts("");
  703. puts(" -add-service service#name@buildSet=<value>");
  704. puts("For examples:");
  705. puts(" -add-service esdl#dynamicesdl@buildSet=DynamicESDL");
  706. puts("");
  707. puts(" -add-binding <esp name>@name=<binding name>^service=<service name>[^port=<value>]");
  708. puts(" -mod-binding <esp name>:<binding name>@<attr>=<value>");
  709. puts(" -rmv-binding <esp name>:<binding name>");
  710. puts("For examples:");
  711. puts(" -add-binding myesp@name=mydesdl^service=dynamicesdl^port=8043");
  712. puts(" -mod-binding myesp:mydesdl@port=8050");
  713. puts(" -rmv-binding myesp:mydesdl");
  714. puts("");
  715. puts(" -add-topology name|clone:cluster@name=<value>:roxie@process=<value>:eclcc@process=<value>:eclegent@process=<value> ");
  716. puts(" To add default topology: -add-topology default");
  717. puts(" -mod-topology <topology name>:<cluster name>:eclagent@process=<value>");
  718. puts(" -rmv-topology <topology name>:cluster#name>:eclagent@process=<value>");
  719. puts("For examples:");
  720. puts(" -add-topology topology:cluster@name=cluster2:roxie@process=roxie2:eclcc@process=eclcc2:eclagent@process=agent2 ");
  721. puts("");
  722. }
  723. void CEnvGen::usage_update_input_format_2()
  724. {
  725. // add xxx-binding and xxx-service
  726. puts("");
  727. puts("These options are for updating environment with one line format.");
  728. puts(" -add category(hd:sw:pg):comp(esp|computer)#name[:selector(instance|dir|<relative xpath>)]@attr=value");
  729. puts(" -mod category(hd:sw:pg):comp(esp|computer)#name[:selelctor(instance|dir|<xpath>)]@attr1=value|old");
  730. puts(" -rmv category(hd:sw:pg):comp@name(service@ws_ecl|computer@localhost):target<xpath to delete>:selector<condition>(instance|dir|<relative xpath>):attr=value|old");
  731. puts("For examples:");
  732. puts(" -add sw:roxie#myroxie:instance@ip=1.0.0.22;1.0.0.23");
  733. puts(" -mod sw:dali#mydali:instance@ip=1.0.0.20");
  734. puts(" -mod sw:thor#mythor@channelsPerSlave=4");
  735. puts(" -mod sw:backupnode#mybackupnode:NodeGroup@name=thor2");
  736. puts(" -rmv hd:computer@ip=1.1.0.30");
  737. puts("");
  738. }
  739. void CEnvGen::usage_update_input_format_3()
  740. {
  741. puts("");
  742. puts("This option is for updating environment with in either XML format.");
  743. puts(" -in-file <input-file-name>.xml");
  744. puts(" format:");
  745. puts("<Env>");
  746. puts(" <Config");
  747. puts(" env-in=[input environment file]");
  748. puts(" env-out|env=[output environment file]");
  749. puts(" mode=[create|update]");
  750. puts(" ip-list=[single ip or ip list separated by ;]");
  751. puts(" ip-file=[ip file with one ip per line end with ;]");
  752. puts(" support-nodes=[num of support nodes]");
  753. puts(" esp-nodes=[num of esp nodes]");
  754. puts(" roxie-nodes=[num of roxie nodes]");
  755. puts(" thor-nodes=[num of thor nodes]");
  756. puts(" slaves-per-node=[num of slaves per node]");
  757. puts(" roxie-on-demand=[true|false]");
  758. puts(" options=[environment.conf full path]");
  759. puts(" rules=[genrules.conf full path]");
  760. puts(" buildset=[buidset.xml full path]");
  761. puts(" >");
  762. puts(" <Task category=[hardware|software|programs|envsettings]");
  763. puts(" component=[computer|dali|esp|roxie|thor|topology|service|...]");
  764. puts(" key=[component name list separated by \",\"");
  765. puts(" operation=[add|modify|remove]");
  766. puts(" target=[node|attribure|child] <!- These are remove target. The default is node -->");
  767. puts(" selector=[xpath] <!- xpath of node to apply the operation. Such as \"instance\" -->");
  768. puts(" selector-key=[selector unique attribute]");
  769. puts(" id=[node id] <!- with this no category, component, key, selector and selector-key are needed -->");
  770. puts(" >");
  771. puts(" <Attributes>");
  772. puts(" <Attribute name=[attribute name] value=[attribute value] oldValue=[old value]/>");
  773. puts(" ......");
  774. puts(" </Attributes>");
  775. puts(" <Children>");
  776. puts(" <Child name=[value]>");
  777. puts(" <Attributes>");
  778. puts(" <Attribute name=[attribute name] value=[attribute value] oldValue=[old value]/>");
  779. puts(" ......");
  780. puts(" </Attributes>");
  781. puts(" </Child>");
  782. puts(" ......");
  783. puts(" </Children>");
  784. puts(" </Task>");
  785. puts("</Config></Env>");
  786. puts("For example:");
  787. puts(" <Env>");
  788. puts(" <Config env-in=\"/tmp/environment_in.xml\" env-out=\"/tmp/environment_out.xml\" mode=\"update\">");
  789. puts(" <Task category=\"Hardware\" component=\"computer\" operation=\"modify\">");
  790. puts(" <Attributes>");
  791. puts(" <Attribute name=\"ip\" oldValue=\"1.0.0.30\" value=\"1.1.0.50\"/>");
  792. puts(" </Attributes>");
  793. puts(" </Task>");
  794. puts(" </Config>");
  795. puts(" </Env>");
  796. puts("");
  797. }
  798. void CEnvGen::usage_update_input_format_3_json()
  799. {
  800. puts("");
  801. puts("This option is for updating environment with in either JSON format.");
  802. puts(" -in-file <input-file-name>.json");
  803. puts(" For exmaple:");
  804. puts("{");
  805. puts(" \"Config\": {");
  806. puts(" \"@env-in\": \".\\/src\\/templates\\/env_base.xml\",");
  807. puts(" \"@env-out\": \"\\/tmp\\/envgen2_test\\/roxie_add_ip_1.xml\",");
  808. puts(" \"@mode\": \"update\",");
  809. puts(" \"Task\": {");
  810. puts(" \"@category\": \"Software\",");
  811. puts(" \"@component\": \"roxie\",");
  812. puts(" \"@key\": \"myroxie\",");
  813. puts(" \"@operation\": \"add\",");
  814. puts(" \"@selector\": \"instance\",");
  815. puts(" \"Attributes\": {");
  816. puts(" \"Attribute\": {");
  817. puts(" \"@name\": \"ip\",");
  818. puts(" \"@value\": \"1.0.0.22\"");
  819. puts(" }");
  820. puts(" }");
  821. puts(" }");
  822. puts(" }");
  823. puts("}");
  824. puts("");
  825. }
  826. void CEnvGen::addUpdateTaskFromFile(const char * inFile)
  827. {
  828. Owned<IPropertyTree> inPTree;
  829. if ((String(inFile).toLowerCase())->endsWith(".json"))
  830. {
  831. StringBuffer sbFile;
  832. sbFile.loadFile(inFile);
  833. inPTree.setown(createPTreeFromJSONString(sbFile.str()));
  834. }
  835. else
  836. {
  837. inPTree.setown(createPTreeFromXMLFile(inFile));
  838. }
  839. // add Config attributies to params
  840. IPropertyTree *pCfg = m_params->queryPropTree("Config");
  841. assert(pCfg);
  842. Owned<IAttributeIterator> attrIter = inPTree->getAttributes();
  843. ForEach(*attrIter)
  844. {
  845. const char* propName = attrIter->queryName();
  846. if (!(*propName)) continue;
  847. pCfg->setProp(propName, attrIter->queryValue());
  848. }
  849. // add Tasks to params
  850. Owned<IPropertyTreeIterator> taskIter = inPTree->getElements("Task");
  851. ForEach(*taskIter)
  852. {
  853. IPropertyTree* task = &taskIter->query();
  854. StringBuffer sb;
  855. toXML(task, sb);
  856. pCfg->addPropTree("Task", createPTreeFromXMLString(sb.str()));
  857. }
  858. }
  859. bool CEnvGen::convertOverrideTask(IPropertyTree *config, const char * input)
  860. {
  861. StringArray sbarr;
  862. sbarr.appendList(input, ",");
  863. StringArray sbarrXPath;
  864. sbarrXPath.appendList(sbarr.item(1), "@");
  865. StringBuffer sbTask;
  866. sbTask.clear().appendf("sw:%s", sbarr.item(0));
  867. if (sbarrXPath.ordinality() < 2)
  868. {
  869. fprintf(stderr, "Override xpath miss '@'\n");
  870. return false;
  871. }
  872. if ((sbarrXPath.ordinality() == 2) && !(*sbarrXPath.item(0)))
  873. sbTask.appendf("@%s=%s", sbarrXPath.item(1), sbarr.item(2));
  874. else
  875. {
  876. sbTask.appendf(":selector=%s", sbarrXPath.item(0));
  877. for (unsigned i=1; i < sbarrXPath.ordinality()-1; i++)
  878. sbTask.appendf("#%s", sbarrXPath.item(i));
  879. sbTask.appendf("@%s=%s", sbarrXPath.item(sbarrXPath.ordinality()-1), sbarr.item(2));
  880. }
  881. createUpdateTask("modify", config, sbTask.str());
  882. return true;
  883. }
  884. void CEnvGen::cloudConfiguration(IPropertyTree * config, const char* cloud)
  885. {
  886. if (!stricmp(cloud, "aws"))
  887. {
  888. createUpdateTask("modify", config, "sw:espsmc@enableSystemUseRewrite=true|false");
  889. createUpdateTask("modify", config, "sw:roxie@roxieMulticastEnabled=false");
  890. }
  891. }
  892. int main(int argc, char** argv)
  893. {
  894. InitModuleObjects();
  895. //CEnvGen * envGen = new CEnvGen();
  896. CEnvGen envGen;
  897. try {
  898. if (!envGen.parseArgs(argc, argv))
  899. {
  900. // delete envGen;
  901. return 1;
  902. }
  903. envGen.process();
  904. }
  905. catch (IException* e)
  906. {
  907. int errCode = e->errorCode();
  908. StringBuffer errMsg;
  909. e->errorMessage(errMsg);
  910. printf("Error: %d, %s\n", errCode, errMsg.str());
  911. e->Release();
  912. // delete envGen;
  913. return 1;
  914. }
  915. //delete envGen;
  916. return 0;
  917. }