main.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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 "jliball.hpp"
  14. #include "XMLTags.h"
  15. #include "deployutils.hpp"
  16. #include "build-config.h"
  17. #define ENVGEN_PATH_TO_ESP_CONFIG INSTALL_DIR "" CONFIG_DIR "/configmgr/esp.xml"
  18. #define STANDARD_CONFIGXMLDIR COMPONENTFILES_DIR"/configxml/"
  19. #define STANDARD_CONFIG_BUILDSETFILE "buildset.xml"
  20. bool validateInteger(const char *str,int &out)
  21. {
  22. bool bIsValid = false;
  23. char *end = NULL;
  24. errno = 0;
  25. const long sl = strtol(str,&end,10);
  26. if (end == str)
  27. {
  28. fprintf(stderr, "Error: non-integer parameter '%s' specified.\n",str);
  29. }
  30. else if ('\0' != *end)
  31. {
  32. fprintf(stderr, "Error: non-integer characters found in '%s' when expecting integer input.\n",str);
  33. }
  34. else if ( (INT_MAX < sl || INT_MIN > sl) || ((LONG_MIN == sl || LONG_MAX == sl) && ERANGE == errno))
  35. {
  36. fprintf(stderr, "Error: integer '%s' is out of range.\n",str);
  37. }
  38. else
  39. {
  40. out = (int)sl;
  41. bIsValid = true;
  42. }
  43. return bIsValid;
  44. }
  45. void usage()
  46. {
  47. const char* version = "1.1";
  48. printf("HPCC Systems® environment generator. version %s. Usage:\n", version);
  49. puts(" envgen -env <environment file> -ip <ip addr> [options]");
  50. puts("");
  51. puts("options: ");
  52. puts(" -env : Full path of the environment file that will be generated.");
  53. puts(" If a file with the same name exists, a new name with _xxx ");
  54. puts(" will be generated ");
  55. puts(" -ip : Ip addresses that should be used for environment generation");
  56. puts(" Allowed formats are ");
  57. puts(" X.X.X.X;");
  58. puts(" X.X.X.X-XXX;");
  59. puts(" -ipfile: name of the file that contains Ip addresses");
  60. puts(" Allowed formats are ");
  61. puts(" X.X.X.X;");
  62. puts(" X.X.X.X-XXX;");
  63. puts(" -supportnodes <number of support nodes>: Number of nodes to be used");
  64. puts(" for non-Thor and non-Roxie components. If not specified or ");
  65. puts(" specified as 0, thor and roxie nodes may overlap with support");
  66. puts(" nodes. If an invalid value is provided, support nodes are ");
  67. puts(" treated to be 0");
  68. puts(" -roxienodes <number of roxie nodes>: Number of nodes to be generated ");
  69. puts(" for roxie. If not specified or specified as 0, no roxie nodes");
  70. puts(" are generated");
  71. puts(" -thornodes <number of thor nodes>: Number of nodes to be generated ");
  72. puts(" for thor slaves. A node for thor master is automatically added. ");
  73. puts(" If not specified or specified as 0, no thor nodes");
  74. puts(" are generated");
  75. puts(" -espnodes <number of esp nodes>: Number of nodes to be generated ");
  76. puts(" If not specified 1 esp node is generated");
  77. puts(" If 0 is specified then all available nodes specified with assign_ips flag ");
  78. puts(" will be used, others 0 esp nodes will be generated.");
  79. puts(" If greater than 1 instance is specified, -assign_ips for esp is required to be set.");
  80. puts(" -slavesPerNode <number of thor slaves per node>: Number of thor nodes ");
  81. puts(" per slave.");
  82. puts(" -thorChannelsPerSlave <number of channels per thor slave>: Number of thor channels per slave.");
  83. puts(" The default is 1.");
  84. puts(" -roxieChannelsPerSlave <number of channels per roxie slave>: Number of roxie channels per slave.");
  85. puts(" The default is 1.");
  86. puts(" -roxieondemand <enable roxie on demand(1) or disable roxie on demand(any ");
  87. puts(" other value)>: Enable roxie on demand by specifying 1 for flag. ");
  88. puts(" Any other value will disable roxie on demand");
  89. puts(" -o <categoryname=newdirvalue>: overrides for any common directories");
  90. puts(" There can be multiple of the -o options. Each override should still");
  91. puts(" contain a [NAME] and either a [CATEGORY] or [INST]. ");
  92. puts(" If category already exists, the directory value is updated. Otherwise");
  93. puts(" a new category is created.");
  94. puts(" For example, \"-o log=/var/logs/[NAME]/mylogs/[INST] -o run=/var/run/[NAME]/myrun/[INST]\"");
  95. puts(" -override <buildset,xpath,value>: overrides all component properties with the");
  96. puts(" given xpath for the given buildset with the provided value. If the xpath is");
  97. puts(" not already present, it is added to any of the components");
  98. puts(" There can be multiple of the -override options. For example, to override the dropzone");
  99. puts(" directory and to set eclwatch's enableSystemUseRewrite to true, the following options");
  100. puts(" can be provided.");
  101. puts(" \"-override DropZone,@directory,/mnt/disk1/mydropzone ");
  102. puts(" -override espsmc,@enableSystemUseRewrite,true\"");
  103. puts(" -set_xpath_attrib_value <XPATH> <ATTRIBUTE> <VALUE>: sets or add the xpath with attribute and value.");
  104. puts(" Example: \"-set_xpath_attrib_value Software/Topology/Cluster[@name=\"thor\"]/ThorCluster @process thor123\"");
  105. puts(" -assign_ips <BuildSet> <IP or IP Range>: assign IPs to specific buildset components");
  106. puts(" Example: \" -assign_ips dali 10.0.0.1-10");
  107. puts(" -help: print out this usage.");
  108. }
  109. int main(int argc, char** argv)
  110. {
  111. InitModuleObjects();
  112. const char* out_envname = NULL;
  113. const char* in_ipfilename;
  114. StringBuffer ipAddrs;
  115. int roxieNodes=1, thorNodes=1, slavesPerNode=1, supportNodes=1, espNodes=1, thorChannelsPerSlave=1, roxieChannelsPerSlave=1;
  116. bool roxieOnDemand = true;
  117. MapStringTo<StringBuffer> dirMap;
  118. StringArray overrides;
  119. StringBufferArray arrXPaths;
  120. StringBufferArray arrAttrib;
  121. StringBufferArray arrValues;
  122. StringArray arrAssignIPRanges;
  123. StringArray arrBuildSetWithAssignedIPs;
  124. int i = 1;
  125. bool writeToFiles = false;
  126. int port = 80;
  127. while(i<argc)
  128. {
  129. if(stricmp(argv[i], "-help") == 0 || stricmp(argv[i], "-?") == 0)
  130. {
  131. usage();
  132. releaseAtoms();
  133. return 0;
  134. }
  135. else if (stricmp(argv[i], "-set_xpath_attrib_value")== 0)
  136. {
  137. i++;
  138. arrXPaths.append(*new StringBufferItem (argv[i++]));
  139. arrAttrib.append(*new StringBufferItem (argv[i++]));
  140. arrValues.append(*new StringBufferItem (argv[i++]));
  141. }
  142. else if (stricmp(argv[i], "-env") == 0)
  143. {
  144. i++;
  145. out_envname = argv[i++];
  146. }
  147. else if (stricmp(argv[i], "-supportnodes") == 0)
  148. {
  149. i++;
  150. if (validateInteger(argv[i++],supportNodes) != true)
  151. {
  152. releaseAtoms();
  153. return 1;
  154. }
  155. }
  156. else if (stricmp(argv[i], "-roxienodes") == 0)
  157. {
  158. i++;
  159. if (validateInteger(argv[i++],roxieNodes) != true)
  160. {
  161. releaseAtoms();
  162. return 1;
  163. }
  164. }
  165. else if (stricmp(argv[i], "-thornodes") == 0)
  166. {
  167. i++;
  168. if (validateInteger(argv[i++],thorNodes) != true)
  169. {
  170. releaseAtoms();
  171. return 1;
  172. }
  173. }
  174. else if (stricmp(argv[i], "-espnodes") == 0)
  175. {
  176. i++;
  177. if (validateInteger(argv[i++],espNodes) != true)
  178. {
  179. releaseAtoms();
  180. return 1;
  181. }
  182. }
  183. else if (stricmp(argv[i], "-slavespernode") == 0)
  184. {
  185. i++;
  186. if (validateInteger(argv[i++],slavesPerNode) != true)
  187. {
  188. releaseAtoms();
  189. return 1;
  190. }
  191. }
  192. else if (stricmp(argv[i], "-thorchannelsperslave") == 0)
  193. {
  194. i++;
  195. if (validateInteger(argv[i++],thorChannelsPerSlave) != true)
  196. {
  197. releaseAtoms();
  198. return 1;
  199. }
  200. }
  201. else if (stricmp(argv[i], "-roxiechannelsperslave") == 0)
  202. {
  203. i++;
  204. if (validateInteger(argv[i++],roxieChannelsPerSlave) != true)
  205. {
  206. releaseAtoms();
  207. return 1;
  208. }
  209. }
  210. else if (stricmp(argv[i], "-roxieondemand") == 0)
  211. {
  212. i++;
  213. int iConverted = 0;
  214. if (validateInteger(argv[i++],iConverted) != true)
  215. {
  216. releaseAtoms();
  217. return 1;
  218. }
  219. if (iConverted != 1)
  220. {
  221. roxieOnDemand = false;
  222. }
  223. }
  224. else if (stricmp(argv[i], "-ip") == 0)
  225. {
  226. i++;
  227. ipAddrs.append(argv[i++]);
  228. }
  229. else if(stricmp(argv[i], "-ipfile") == 0)
  230. {
  231. i++;
  232. in_ipfilename = argv[i++];
  233. ipAddrs.loadFile(in_ipfilename);
  234. }
  235. else if(stricmp(argv[i], "-o") == 0)
  236. {
  237. i++;
  238. StringArray sbarr;
  239. sbarr.appendList(argv[i++], "=");
  240. if (sbarr.length() != 2)
  241. continue;
  242. if (strstr(sbarr.item(1), "[NAME]") && (strstr(sbarr.item(1), "[INST]") || strstr(sbarr.item(1), "[COMPONENT]")))
  243. dirMap.setValue(sbarr.item(0), sbarr.item(1));
  244. else
  245. {
  246. fprintf(stderr, "Error: Directory Override must contain [NAME] and either [INST] or [COMPONENT]\n");
  247. releaseAtoms();
  248. return 1;
  249. }
  250. }
  251. else if(stricmp(argv[i], "-override") == 0)
  252. {
  253. i++;
  254. overrides.append(argv[i++]);
  255. }
  256. else if(stricmp(argv[i], "-assign_ips") == 0)
  257. {
  258. i++;
  259. arrBuildSetWithAssignedIPs.append(argv[i++]);
  260. arrAssignIPRanges.append(argv[i++]);
  261. }
  262. else
  263. {
  264. fprintf(stderr, "Error: unknown command line parameter: %s\n", argv[i]);
  265. usage();
  266. releaseAtoms();
  267. return 1;
  268. }
  269. }
  270. if (!out_envname)
  271. {
  272. fprintf(stderr, "Error: Output environment xml file is required. Please specify.\n");
  273. usage();
  274. releaseAtoms();
  275. return 1;
  276. }
  277. if (ipAddrs.length() == 0)
  278. {
  279. fprintf(stderr, "Error: Ip addresses are required. Please specify.\n");
  280. usage();
  281. releaseAtoms();
  282. return 1;
  283. }
  284. try
  285. {
  286. validateIPS(ipAddrs.str());
  287. for (unsigned nIdx = 0; nIdx < arrAssignIPRanges.length(); nIdx++)
  288. {
  289. validateIPS(arrAssignIPRanges.item(nIdx));
  290. }
  291. StringBuffer optionsXml, envXml;
  292. const char* pServiceName = "WsDeploy_wsdeploy_esp";
  293. Owned<IPropertyTree> pCfg = createPTreeFromXMLFile(ENVGEN_PATH_TO_ESP_CONFIG);
  294. optionsXml.appendf("<XmlArgs supportNodes=\"%d\" roxieNodes=\"%d\" thorNodes=\"%d\" espNodes=\"%d\" slavesPerNode=\"%d\" thorChannelsPerSlave=\"%d\" roxieChannelsPerSlave=\"%d\" roxieOnDemand=\"%s\" ipList=\"%s\"/>", supportNodes, roxieNodes,
  295. thorNodes, espNodes, slavesPerNode, thorChannelsPerSlave, roxieChannelsPerSlave, roxieOnDemand?"true":"false", ipAddrs.str());
  296. buildEnvFromWizard(optionsXml, pServiceName, pCfg, envXml, arrBuildSetWithAssignedIPs, arrAssignIPRanges, &dirMap);
  297. if(envXml.length())
  298. {
  299. if (overrides.length() || arrXPaths.length())
  300. {
  301. Owned<IPropertyTree> pEnvTree = createPTreeFromXMLString(envXml.str());
  302. for(unsigned i = 0; i < overrides.ordinality() ; i++)
  303. {
  304. StringArray sbarr;
  305. sbarr.appendList(overrides.item(i), ",");
  306. if (sbarr.length() != 3)
  307. {
  308. fprintf(stderr, "\nWarning: unable to override %s as override option needs 3 valid values to override.\n", overrides.item(i));
  309. continue;
  310. }
  311. const char* buildset = sbarr.item(0);
  312. bool flag = false;
  313. if (buildset && *buildset)
  314. {
  315. StringBuffer xpath(XML_TAG_SOFTWARE"/");
  316. xpath.appendf("*[" XML_ATTR_BUILDSET "='%s']", buildset);
  317. Owned<IPropertyTreeIterator> iter = pEnvTree->getElements(xpath.str());
  318. ForEach (*iter)
  319. {
  320. flag = true;
  321. IPropertyTree* pComp = &iter->query();
  322. const char* prop = sbarr.item(1);
  323. if (prop && *prop)
  324. pComp->setProp(prop, sbarr.item(2));
  325. }
  326. }
  327. if (!buildset || !*buildset || !flag)
  328. fprintf(stderr, "\nWarning: unable to find components of buildset '%s' for override option '%s'.\n", buildset?buildset:"", overrides.item(i));
  329. }
  330. if (arrXPaths.length() > 0)
  331. {
  332. unsigned nCount = 0;
  333. while (nCount < arrXPaths.length())
  334. {
  335. IPropertyTree *attrTree = pEnvTree->queryPropTree(arrXPaths.item(nCount).str());
  336. if (attrTree == NULL)
  337. {
  338. attrTree = createPTree();
  339. attrTree->appendProp(arrAttrib.item(nCount).str(), arrValues.item(nCount).str());
  340. pEnvTree->setPropTree(arrXPaths.item(nCount).str(), attrTree);
  341. }
  342. else
  343. attrTree->setProp(arrAttrib.item(nCount).str(), arrValues.item(nCount).str());
  344. nCount++;
  345. }
  346. }
  347. toXML(pEnvTree, envXml.clear());
  348. }
  349. StringBuffer env;
  350. StringBuffer thisip;
  351. queryHostIP().getIpText(thisip);
  352. env.appendf("<" XML_HEADER ">\n<!-- Generated with envgen on ip %s -->\n", thisip.str());
  353. env.append(envXml);
  354. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(false);
  355. Owned<IConstEnvironment> constEnv = factory->loadLocalEnvironment(env);
  356. validateEnv(constEnv);
  357. Owned<IFile> pFile;
  358. pFile.setown(createIFile(out_envname));
  359. Owned<IFileIO> pFileIO;
  360. pFileIO.setown(pFile->open(IFOcreaterw));
  361. pFileIO->write(0, env.length(), env.str());
  362. }
  363. }
  364. catch(IException *excpt)
  365. {
  366. StringBuffer errMsg;
  367. fprintf(stderr, "Exception: %d:\n%s\n", excpt->errorCode(), excpt->errorMessage(errMsg).str());
  368. releaseAtoms();
  369. excpt->Release();
  370. return 1;
  371. }
  372. catch(...)
  373. {
  374. fprintf(stderr, "Unknown exception\n");
  375. releaseAtoms();
  376. return 1;
  377. }
  378. releaseAtoms();
  379. return 0;
  380. }