espconfiggenengine.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 "espconfiggenengine.hpp"
  20. #include <vector>
  21. #include <set>
  22. using std::set;
  23. using std::string;
  24. //---------------------------------------------------------------------------
  25. // CEspConfigGenEngine
  26. //---------------------------------------------------------------------------
  27. CEspConfigGenEngine::CEspConfigGenEngine(IEnvDeploymentEngine& envDepEngine,
  28. IDeploymentCallback& callback,
  29. IPropertyTree& process, const char* inputDir,
  30. const char* outputDir)
  31. : CConfigGenEngine(envDepEngine, callback, process, inputDir, outputDir, "./Instance")
  32. {
  33. }
  34. //---------------------------------------------------------------------------
  35. // check
  36. //---------------------------------------------------------------------------
  37. void CEspConfigGenEngine::check()
  38. {
  39. CConfigGenEngine::check();
  40. // Make sure all protocol and service referenced by bindings are valid
  41. Owned<IPropertyTreeIterator> iter = m_process.getElements("EspBinding");
  42. for (iter->first(); iter->isValid(); iter->next())
  43. {
  44. IPropertyTree* pBinding = &iter->query();
  45. const char* service = pBinding->queryProp("@service");
  46. if (service)
  47. {
  48. if (!lookupProcess("EspService", service))
  49. throw MakeStringException(0, "Process %s references unknown service %s", m_name.get(), service);
  50. }
  51. else
  52. throw MakeStringException(-1, "The ESP binding %s for ESP %s has missing service information!",
  53. pBinding->queryProp("@name"), m_name.get());
  54. }
  55. // Make sure DaliServers are valid
  56. iter.setown(m_process.getElements(".//*[@daliServers]"));
  57. ForEach(*iter)
  58. {
  59. const char* name = iter->query().queryProp("@daliServers");
  60. if (name && *name && !lookupProcess("DaliServerProcess", name))
  61. throw MakeStringException(0, "Process %s references unknown DaliServers %s", m_name.get(), name);
  62. }
  63. // Make sure EclServer is valid
  64. iter.setown(m_process.getElements(".//*[@eclServer]"));
  65. ForEach(*iter)
  66. {
  67. const char* name = iter->query().queryProp("@eclServer");
  68. if (name && *name && !lookupProcess("EclServerProcess", name))
  69. throw MakeStringException(0, "Process %s references unknown EclServer %s", m_name.get(), name);
  70. }
  71. // Make sure AttributeServer is valid
  72. iter.setown(m_process.getElements(".//*[@attributeServer]"));
  73. ForEach(*iter)
  74. {
  75. const char* name = iter->query().queryProp("@attributeServer");
  76. if (name && *name && !lookupProcess("AttrServerProcess", name))
  77. throw MakeStringException(0, "Process %s references unknown AttributeServer %s", m_name.get(), name);
  78. }
  79. }
  80. //---------------------------------------------------------------------------
  81. // createInstallFileMap
  82. //---------------------------------------------------------------------------
  83. int CEspConfigGenEngine::determineInstallFiles(IPropertyTree& node, CInstallFiles& installFiles) const
  84. {
  85. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Merging file lists for ESP server and its bound service(s) ...");
  86. const char* myBuild = m_process.queryProp("@build");
  87. //process bindings for this esp process and add files for each service used by
  88. //each binding before adding files for this esp process
  89. Owned<IPropertyTreeIterator> iBinding = m_process.getElements("EspBinding");
  90. ForEach(*iBinding)
  91. {
  92. IPropertyTree* pBinding = &iBinding->query();
  93. const char* szService = pBinding->queryProp("@service");
  94. // Lookup plugin process
  95. IPropertyTree* pService = lookupProcess("EspService", szService);
  96. if (!pService)
  97. throw MakeStringException(0, "Process %s references unknown esp service '%s'", m_name.get(), szService);
  98. const char* pszBuild = pService->queryProp("@build");
  99. if (!pszBuild || 0 != strcmp(pszBuild, myBuild))
  100. throw MakeStringException(0, "ESP service '%s' used by ESP process '%s'\n has a different build (%s) to its ESP process!",
  101. szService, m_name.get(), pszBuild);
  102. // Get plugin file list from the plugin process
  103. CConfigGenEngine::determineInstallFiles(*pService, installFiles);
  104. }
  105. int rc = CConfigGenEngine::determineInstallFiles(node, installFiles);
  106. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "determineInstallFiles complete");
  107. return rc;
  108. }
  109. //---------------------------------------------------------------------------
  110. // processCustomMethod
  111. //---------------------------------------------------------------------------
  112. void CEspConfigGenEngine::processCustomMethod(const char *method, const char *source, const char *outputFile,
  113. const char *instanceName, EnvMachineOS os)
  114. {
  115. if (!stricmp(method, "ssl_certificate"))
  116. {
  117. //we only need to worry about SSL certificates and private keys if https is being used
  118. //by any of our bindings
  119. //
  120. Owned<IPropertyTreeIterator> it = m_process.getElements("EspBinding[@protocol='https']");
  121. if (!it->first())
  122. return;
  123. }
  124. CConfigGenEngine::processCustomMethod(method, source, outputFile, instanceName, os);
  125. }
  126. //---------------------------------------------------------------------------
  127. // xslTransform
  128. //---------------------------------------------------------------------------
  129. void CEspConfigGenEngine::xslTransform(
  130. const char *xslFilePath, const char *outputFilePath,
  131. const char* instanceName, EnvMachineOS os/*=MachineOsUnknown*/,
  132. const char* processName/*=NULL*/,
  133. bool isEspModuleOrPlugin/*=false*/)
  134. {
  135. m_createIni = false;
  136. // Skip if not processing config files
  137. checkAbort();
  138. if (!m_compare)
  139. ensurePath(outputFilePath);
  140. if (m_compare)
  141. outputFilePath = setCompare(outputFilePath);
  142. if (instanceName)
  143. {
  144. m_transform->setParameter("instance", StringBuffer("'").append(instanceName).append("'").str());
  145. const char* szXslFileName = pathTail(xslFilePath);
  146. if (!stricmp(szXslFileName, "esp.xsl"))
  147. {
  148. //disable compare since these transforms are needed by us in any case for esp.xml
  149. const bool bCompare = m_compare;
  150. m_compare = false;
  151. //we need to pass in a list of file names created as a result of individual esp service modules
  152. //running xslt using method xslt_esp_service on their own service specific XSL files as specified
  153. //in install set (created by release_<service>.bat
  154. //
  155. //esp.xsl merges these in the output under /Environment/Software/EspProcess
  156. //
  157. StringBuffer serviceXsltOutputFiles;
  158. processServiceModules("esp_plugin", serviceXsltOutputFiles, instanceName, os);
  159. processServiceModules("esp_service_module", serviceXsltOutputFiles, instanceName, os);
  160. m_compare = bCompare;
  161. IEnvDeploymentEngine& envDepEngine = getEnvDepEngine();
  162. const char* srcDaliAddress = envDepEngine.getSourceDaliAddress();
  163. m_transform->setParameter("espServiceName", "''");
  164. m_transform->setParameter("serviceFilesList", StringBuffer("'").append(serviceXsltOutputFiles.str()).append("'").str());
  165. m_transform->setParameter("deployedFromDali", StringBuffer("'").append(srcDaliAddress).append("'").str());
  166. }
  167. }
  168. if (m_deployFlags & DEFLAGS_CONFIGFILES) //are we processing config files?
  169. {
  170. Owned<IDeployTask> task =
  171. createDeployTask(*m_pCallback, "XSL Transform", m_process.queryName(), m_name.get(),
  172. instanceName, xslFilePath, outputFilePath, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os, processName);
  173. m_pCallback->printStatus(task);
  174. task->transformFile(*m_processor, *m_transform, m_cachePath.get());
  175. m_pCallback->printStatus(task);
  176. checkAbort(task);
  177. }
  178. if (m_compare)
  179. compareFiles(os);
  180. }
  181. void CEspConfigGenEngine::processServiceModules(const char* moduleType,
  182. StringBuffer& serviceXsltOutputFiles,
  183. const char* instanceName,
  184. EnvMachineOS os)
  185. {
  186. set<string> serviceNamesProcessed;
  187. bool bEspServiceModule = !stricmp(moduleType, "esp_service_module");
  188. char tempPath[_MAX_PATH];
  189. getTempPath(tempPath, sizeof(tempPath), m_name);
  190. const CInstallFileList& fileList = m_installFiles.getInstallFileList();
  191. CInstallFileList::const_iterator i = fileList.begin();
  192. CInstallFileList::const_iterator iEnd = fileList.end();
  193. for (; i != iEnd; i++)
  194. {
  195. const CInstallFile& installFile = *(*i);
  196. const char* method = installFile.getMethod().c_str();
  197. if (!stricmp(method, moduleType))
  198. {
  199. const char* source = installFile.getSrcPath().c_str();
  200. std::string dest = installFile.getDestPath().c_str();
  201. //our base class method CConfigGenEngine::determineInstallFiles() encoded
  202. //dest is of the format <destpath>+<service name> so extract both of the parts
  203. //
  204. std::string::size_type pos = dest.find_last_of('+');
  205. std::string serviceName = dest.substr(pos+1);
  206. dest.erase(pos);
  207. if ((pos = dest.find("@temp" PATHSEPSTR)) != std::string::npos)
  208. dest.replace(pos, strlen("@temp" PATHSEPSTR), tempPath);
  209. //if method is esp_service_module then check to see if not processing config files
  210. //
  211. bool bProcess = true;
  212. if (bEspServiceModule)
  213. {
  214. if (m_deployFlags & DEFLAGS_CONFIGFILES)
  215. {
  216. //each esp_service_module for a given service name is expected to produce necessary
  217. //and sufficient information for itself (EspService node) and all its EspBindings
  218. //(we may have multiple bindings for the same service i.e. EspService[@name='xyz']).
  219. //Therefore, we only need to process one instance of EspService exactly once.
  220. if (serviceNamesProcessed.find(serviceName) != serviceNamesProcessed.end())
  221. continue;
  222. serviceNamesProcessed.insert(serviceName);
  223. serviceXsltOutputFiles.append(dest.c_str());
  224. serviceXsltOutputFiles.append(';');
  225. }
  226. else
  227. bProcess = false;
  228. }
  229. if (bProcess)
  230. {
  231. serviceName.insert(0, "\'");
  232. serviceName += '\'';
  233. m_transform->setParameter("espServiceName", serviceName.c_str());
  234. CConfigGenEngine::xslTransform(source, dest.c_str(), instanceName, os, NULL, true);
  235. }
  236. }
  237. }
  238. }