configgenengine.cpp 17 KB

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