configgenengine.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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 "jptree.hpp"
  15. #include "jmutex.hpp"
  16. #include "jexcept.hpp"
  17. #include "environment.hpp"
  18. #include "xslprocessor.hpp"
  19. #include "configgenengine.hpp"
  20. #include "XMLTags.h"
  21. #ifdef _WINDOWS
  22. #define CONFIGGEN_COMP_LIST "cgencomplist_win.xml"
  23. #else
  24. #define CONFIGGEN_COMP_LIST "cgencomplist_linux.xml"
  25. #endif
  26. //---------------------------------------------------------------------------
  27. // CEspDeploymentEngine
  28. //---------------------------------------------------------------------------
  29. CConfigGenEngine::CConfigGenEngine(IEnvDeploymentEngine& envDepEngine,
  30. IDeploymentCallback& callback, IPropertyTree& process,
  31. const char* inputDir, const char* outputDir,
  32. const char* instanceType, bool createIni)
  33. : CDeploymentEngine(envDepEngine, callback, process, instanceType, createIni),m_inDir(inputDir), m_outDir(outputDir)
  34. {
  35. m_useSSHIfDefined = false;
  36. }
  37. //---------------------------------------------------------------------------
  38. // determineInstallFiles
  39. //---------------------------------------------------------------------------
  40. int CConfigGenEngine::determineInstallFiles(IPropertyTree& processNode, CInstallFiles& installFiles) const
  41. {
  42. try
  43. {
  44. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  45. "Determining files to install for %s", processNode.queryProp("@name"));
  46. StringBuffer compListPath(CONFIGGEN_COMP_LIST);
  47. if (m_inDir.length())
  48. compListPath.clear().append(m_inDir).append(PATHSEPCHAR).append(CONFIGGEN_COMP_LIST);
  49. Owned<IPropertyTree> deployNode = createPTreeFromXMLFile(compListPath.str(), ipt_caseInsensitive);
  50. StringBuffer srcFilePath;
  51. srcFilePath.ensureCapacity(_MAX_PATH);
  52. const bool bFindStartable = &m_process == &processNode && m_startable == unknown;
  53. const bool bFindStoppable = &m_process == &processNode && m_stoppable == unknown;
  54. StringBuffer xpath;
  55. xpath.appendf("Component[@name=\"%s\"]",processNode.queryProp("@buildSet"));
  56. IPropertyTree* pComponent = deployNode->queryPropTree(xpath.str());
  57. if (!pComponent)
  58. {
  59. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  60. "Cannot find files to install for %s", processNode.queryProp("@buildSet"));
  61. return 0;
  62. }
  63. Owned<IPropertyTreeIterator> iter = pComponent->getElements("File");
  64. ForEach(*iter)
  65. {
  66. IPropertyTree* pFile = &iter->query();
  67. const char* name = pFile->queryProp("@name");
  68. if (!stricmp(name, "deploy_map.xml"))
  69. continue;
  70. if (bFindStartable && !strnicmp(name, "startup", sizeof("startup")-1))
  71. m_startable = yes;
  72. if (bFindStoppable && !strnicmp(name, "stop", sizeof("stop")-1))
  73. m_stoppable = yes;
  74. const char* method = pFile->queryProp("@method");
  75. if (method && !stricmp(method, "schema"))
  76. continue;
  77. //if we are not deploying build files and method is copy then ignore this file
  78. if (!(m_deployFlags & DEFLAGS_BUILDFILES) && (!method || !stricmp(method, "copy")))
  79. continue;
  80. const char* srcPath = pFile->queryProp("@srcPath");
  81. const char* destPath= pFile->queryProp("@destPath");
  82. const char* destName= pFile->queryProp("@destName");
  83. bool bCacheable = pFile->getPropBool("@cache", false);
  84. // Get source filespec
  85. if (srcPath && !strcmp(srcPath, "@temp"))
  86. {
  87. char tempfile[_MAX_PATH];
  88. getTempPath(tempfile, sizeof(tempfile), m_name);
  89. srcFilePath.clear().append(tempfile).append(name);
  90. }
  91. else
  92. {
  93. srcFilePath.clear().append(m_inDir);
  94. //adjust source paths
  95. if (srcPath && 0!=strcmp(srcPath, "."))
  96. {
  97. if (!strncmp(srcPath, "..", 2) && (*(srcPath+2)=='/' || *(srcPath+2)=='\\'))
  98. {
  99. StringBuffer reldir(srcPath);
  100. reldir.replace('/', '\\');
  101. while (!strncmp(reldir.str(), "..\\", 3))
  102. {
  103. srcFilePath.setLength( srcFilePath.length() - 1 ); //remove last char PATHSEPCHAR
  104. const char* tail = pathTail(srcFilePath.str());
  105. srcFilePath.setLength( tail - srcFilePath.str() );
  106. reldir.remove(0, 3);
  107. }
  108. srcFilePath.append(reldir).append(PATHSEPCHAR);
  109. }
  110. else
  111. srcFilePath.append(srcPath).append(PATHSEPCHAR);
  112. }
  113. srcFilePath.append(name);
  114. }
  115. std::string sDestName;
  116. if (method && (!stricmp(method, "esp_service_module") || !stricmp(method, "esp_plugin")))
  117. {
  118. //if this is xsl transformation and we are not generating config files then ignore
  119. //
  120. if (!(m_deployFlags & DEFLAGS_CONFIGFILES) && !stricmp(method, "esp_service_module"))
  121. continue;
  122. //if this file is an esp service module, encode name of service in the dest file name
  123. //so the esp deployment can figure out which service this file belongs to
  124. //
  125. const char* serviceName = processNode.queryProp("@name");
  126. //if destination name is specified then use it otherwise use <service-name>[index of module].xml
  127. sDestName = serviceName;
  128. if (destName)
  129. {
  130. sDestName += '_';
  131. sDestName += destName;
  132. }
  133. else
  134. {
  135. int espServiceModules = m_envDepEngine.incrementEspModuleCount();
  136. if (espServiceModules > 1)
  137. {
  138. char achNum[16];
  139. itoa(espServiceModules, achNum, 10);
  140. sDestName += achNum;
  141. }
  142. sDestName += ".xml";
  143. }
  144. //encode name of service herein - this is needed by and removed by CEspDeploymentEngine::processServiceModules()
  145. sDestName += '+';
  146. sDestName += processNode.queryProp("@name");//encode the name of service
  147. }
  148. else if (method && (!stricmp(method, "xsl") || !stricmp(method, "xslt")) && !(m_deployFlags & DEFLAGS_CONFIGFILES))
  149. continue;//ignore xsl transformations if we are not generating config files
  150. else
  151. {
  152. if (!method || !*method)
  153. method = "copy";
  154. // Get destination filespec
  155. if (destName && *destName)
  156. {
  157. //we now support attribute names within the destination file names like delimted by @ and + (optional)
  158. //for e.g. segment_@attrib1+_file_@attrib2 would produce segment_attribval1_file_attrib2value
  159. //+ not necessary if the attribute name ends with the word, for e.g. file_@attrib1
  160. //for instnace, suite_@eclServer+.bat would expand to suite_myeclserver.bat
  161. //if this process has an @eclServer with value "myeclserver"
  162. //
  163. if (strchr(destName, '@') || strchr(destName, '+'))
  164. {
  165. char* pszParts = strdup(destName);
  166. char *saveptr;
  167. const char* pszPart = strtok_r(pszParts, "+", &saveptr);
  168. while (pszPart)
  169. {
  170. const char* p = pszPart;
  171. if (*p)
  172. {
  173. if (strchr(p, '@'))//xpath for an attribute?
  174. {
  175. // find name of attribute and replace it with its value
  176. const char* value = m_process.queryProp( p );
  177. if (value)
  178. sDestName.append(value);
  179. }
  180. else
  181. sDestName.append(p); //no attribute so copy verbatim
  182. }
  183. pszPart = strtok_r(NULL, "+", &saveptr);
  184. }
  185. free(pszParts);
  186. }
  187. else
  188. sDestName = destName;
  189. if (sDestName.empty())
  190. throw MakeStringException(-1, "The destination file name '%s' for source file '%s' "
  191. "translates to an empty string!", destName, name);
  192. }
  193. }
  194. StringBuffer destFilePath;
  195. destFilePath.ensureCapacity(_MAX_PATH);
  196. bool bTempFile = (destPath && !stricmp(destPath, "@temp")) ||
  197. !strnicmp(name, "@temp", 5); //@name starts with @temp or @tmp
  198. if (bTempFile)
  199. {
  200. if (sDestName.empty())//dest name not specified
  201. {
  202. if (!strcmp(method, "copy"))
  203. sDestName = name;
  204. else
  205. {
  206. StringBuffer dir;
  207. const char* pszFileName = splitDirTail(name, dir);
  208. const char* pExt = findFileExtension(pszFileName);
  209. if (pExt)
  210. sDestName.append(pszFileName, pExt-pszFileName);
  211. else
  212. sDestName.append(pszFileName);
  213. char index[16];
  214. itoa(m_envDepEngine.incrementTempFileCount(), index, 10);
  215. sDestName.append(index);
  216. if (pExt)
  217. sDestName.append(pExt);
  218. }
  219. }
  220. destFilePath.append("@temp" PATHSEPSTR);
  221. }
  222. else
  223. {
  224. if (destPath && *destPath)
  225. {
  226. destFilePath.append(destPath);
  227. if (destPath[strlen(destPath)-1] != PATHSEPCHAR)
  228. destFilePath.append(PATHSEPCHAR);
  229. }
  230. if (sDestName.empty())
  231. sDestName = name;
  232. }
  233. if (!bTempFile)
  234. destFilePath.append(processNode.queryProp("@name")).append(PATHSEPCHAR);
  235. destFilePath.append(sDestName.c_str());
  236. //For oss, plugins to be handled globally, per Richard.
  237. //esp plugins also end with plugins.xml but they should be handled above.
  238. String destFilePathStr(destFilePath);
  239. String* tmpstr = destFilePathStr.toLowerCase();
  240. if (tmpstr->indexOf("plugins.xml") > 0)
  241. {
  242. delete tmpstr;
  243. createFakePlugins(destFilePath);
  244. continue;
  245. }
  246. delete tmpstr;
  247. //find all occurrences of this destination file in the map and resove any conflicts
  248. //like size mismatch etc.
  249. bool bAddToFileMap = installFiles.resolveConflicts(processNode, method, srcFilePath.str(), destFilePath.str(),
  250. m_name, m_curInstance, NULL);
  251. //resolve conflicts if method is not schema or exec
  252. if (0 != stricmp(method, "schema") && 0 != stricmp(method, "exec") && 0 != strnicmp(method, "del", 3))
  253. {
  254. }
  255. else if (!strnicmp(method, "del", 3))//treat files to be deleted as temp files - to be deleted AFTER we are done!
  256. {
  257. bTempFile = true;
  258. bAddToFileMap = false;
  259. m_envDepEngine.addTempFile(destFilePath.str());
  260. }
  261. if (bAddToFileMap)
  262. {
  263. if (bTempFile)
  264. m_envDepEngine.addTempFile(destFilePath.str());
  265. //enable caching for files to be copied unless expressly asked not to do so
  266. //
  267. if (!bCacheable && !strcmp(method, "copy"))
  268. bCacheable = pFile->getPropBool("@cache", true);
  269. installFiles.addInstallFile(method, srcFilePath.str(), destFilePath.str(), bCacheable, NULL);
  270. }
  271. }
  272. }
  273. catch (IException* e)
  274. {
  275. StringBuffer msg;
  276. e->errorMessage(msg);
  277. e->Release();
  278. throw MakeStringException(0, "Error creating file list for process %s: %s", m_name.get(), msg.str());
  279. }
  280. catch (...)
  281. {
  282. throw MakeErrnoException("Error creating file list for process %s", m_name.get());
  283. }
  284. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, NULL);
  285. return installFiles.getInstallFileList().size();
  286. }
  287. //---------------------------------------------------------------------------
  288. // deployInstance
  289. //---------------------------------------------------------------------------
  290. void CConfigGenEngine::deployInstance(IPropertyTree& instanceNode, bool useTempDir)
  291. {
  292. StringAttr hostDir(m_outDir);
  293. StringAttr destDir(useTempDir ? getDeployDir(instanceNode).str() : hostDir.get());
  294. const char* pszHostDir = hostDir.get();
  295. if (pszHostDir && *pszHostDir==PATHSEPCHAR && *(pszHostDir+1)==PATHSEPCHAR)
  296. connectToHost(instanceNode);
  297. beforeDeployInstance(instanceNode, destDir);
  298. copyInstallFiles(instanceNode, destDir);
  299. afterDeployInstance(instanceNode, destDir);
  300. if (!m_compare && useTempDir)
  301. {
  302. checkAbort();
  303. EnvMachineOS os= m_envDepEngine.lookupMachineOS(instanceNode);
  304. renameDir(hostDir, NULL, os);
  305. renameDir(destDir, hostDir, os);
  306. }
  307. }
  308. void CConfigGenEngine::createFakePlugins(StringBuffer& destFilePath) const
  309. {
  310. String destFilePathStr(destFilePath);
  311. String* tmpstr = destFilePathStr.toLowerCase();
  312. if (!tmpstr->endsWith("plugins.xml"))
  313. {
  314. int index = tmpstr->indexOf("plugins.xml");
  315. destFilePath.remove(index + 11, destFilePath.length() - (index + 11));
  316. }
  317. delete tmpstr;
  318. StringBuffer tmpoutbuf("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Plugins/>");
  319. if (m_instances.ordinality() > 1 && strcmp(m_process.queryName(), XML_TAG_ESPPROCESS))
  320. destFilePath.replaceString("@temp"PATHSEPSTR, m_cachePath);
  321. else
  322. {
  323. char tempPath[_MAX_PATH];
  324. getTempPath(tempPath, sizeof(tempPath), m_name);
  325. ensurePath(tempPath);
  326. destFilePath.replaceString("@temp"PATHSEPSTR, tempPath);
  327. }
  328. Owned<IFile> pTargetFile = createIFile(destFilePath.str());
  329. if (pTargetFile->exists() && pTargetFile->isReadOnly())
  330. pTargetFile->setReadOnly(false);
  331. Owned<IFileIO> pTargetFileIO = pTargetFile->open(IFOcreate);
  332. pTargetFileIO->write( 0, tmpoutbuf.length(), tmpoutbuf.str());
  333. m_envDepEngine.addTempFile(destFilePath.str());
  334. }
  335. //---------------------------------------------------------------------------
  336. // beforeDeploy
  337. //---------------------------------------------------------------------------
  338. void CConfigGenEngine::beforeDeploy()
  339. {
  340. m_installFiles.clear();
  341. char tempPath[_MAX_PATH];
  342. getTempPath(tempPath, sizeof(tempPath), m_name);
  343. m_envDepEngine.addTempDirectory( tempPath );
  344. if (m_instances.ordinality() > 1)
  345. {
  346. strcat(tempPath, "Cache");
  347. char* pszEnd = tempPath + strlen(tempPath);
  348. Owned<IFile> pFile = createIFile(tempPath);
  349. int i = 1;
  350. while (pFile->exists()) { //dir/file exists
  351. itoa(++i, pszEnd, 10);
  352. pFile.setown( createIFile(tempPath) );
  353. }
  354. strcat(tempPath, PATHSEPSTR);
  355. m_cachePath.set( tempPath );
  356. }
  357. else
  358. m_cachePath.set( tempPath );
  359. ensurePath(tempPath);
  360. determineInstallFiles(m_process, m_installFiles);
  361. getCallback().installFileListChanged();
  362. if (m_instances.ordinality() > 1)
  363. {
  364. EnvMachineOS os = m_envDepEngine.lookupMachineOS( m_instances.item(0) );
  365. m_curInstance = "Cache";
  366. copyInstallFiles("Cache", -1, tempPath, os);
  367. }
  368. }