EspDeploymentEngine.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 "EspDeploymentEngine.hpp"
  20. #include <vector>
  21. #include <set>
  22. using std::set;
  23. using std::string;
  24. //---------------------------------------------------------------------------
  25. // CEspDeploymentEngine
  26. //---------------------------------------------------------------------------
  27. CEspDeploymentEngine::CEspDeploymentEngine(IEnvDeploymentEngine& envDepEngine,
  28. IDeploymentCallback& callback,
  29. IPropertyTree& process)
  30. : CDeploymentEngine(envDepEngine, callback, process, "./Instance")
  31. {
  32. }
  33. //---------------------------------------------------------------------------
  34. // check
  35. //---------------------------------------------------------------------------
  36. void CEspDeploymentEngine::check()
  37. {
  38. CDeploymentEngine::check();
  39. // Make sure all protocol and service referenced by bindings are valid
  40. Owned<IPropertyTreeIterator> iter = m_process.getElements("EspBinding");
  41. for (iter->first(); iter->isValid(); iter->next())
  42. {
  43. IPropertyTree* pBinding = &iter->query();
  44. const char* service = pBinding->queryProp("@service");
  45. if (service)
  46. {
  47. if (!lookupProcess("EspService", service))
  48. throw MakeStringException(0, "Process %s references unknown service %s", m_name.get(), service);
  49. }
  50. else
  51. throw MakeStringException(-1, "The ESP binding %s for ESP %s has missing service information!",
  52. pBinding->queryProp("@name"), m_name.get());
  53. }
  54. // Make sure DaliServers are valid
  55. iter.setown(m_process.getElements(".//*[@daliServers]"));
  56. ForEach(*iter)
  57. {
  58. const char* name = iter->query().queryProp("@daliServers");
  59. if (name && *name && !lookupProcess("DaliServerProcess", name))
  60. throw MakeStringException(0, "Process %s references unknown DaliServers %s", m_name.get(), name);
  61. }
  62. // Make sure EclServer is valid
  63. iter.setown(m_process.getElements(".//*[@eclServer]"));
  64. ForEach(*iter)
  65. {
  66. const char* name = iter->query().queryProp("@eclServer");
  67. if (name && *name && !lookupProcess("EclServerProcess", name))
  68. throw MakeStringException(0, "Process %s references unknown EclServer %s", m_name.get(), name);
  69. }
  70. // Make sure AttributeServer is valid
  71. iter.setown(m_process.getElements(".//*[@attributeServer]"));
  72. ForEach(*iter)
  73. {
  74. const char* name = iter->query().queryProp("@attributeServer");
  75. if (name && *name && !lookupProcess("AttrServerProcess", name))
  76. throw MakeStringException(0, "Process %s references unknown AttributeServer %s", m_name.get(), name);
  77. }
  78. }
  79. //---------------------------------------------------------------------------
  80. // createInstallFileMap
  81. //---------------------------------------------------------------------------
  82. int CEspDeploymentEngine::determineInstallFiles(IPropertyTree& node, CInstallFiles& installFiles) const
  83. {
  84. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Merging file lists for ESP server and its bound service(s) ...");
  85. const char* myBuild = m_process.queryProp("@build");
  86. //process bindings for this esp process and add files for each service used by
  87. //each binding before adding files for this esp process
  88. Owned<IPropertyTreeIterator> iBinding = m_process.getElements("EspBinding");
  89. ForEach(*iBinding)
  90. {
  91. IPropertyTree* pBinding = &iBinding->query();
  92. const char* szService = pBinding->queryProp("@service");
  93. // Lookup plugin process
  94. IPropertyTree* pService = lookupProcess("EspService", szService);
  95. if (!pService)
  96. throw MakeStringException(0, "Process %s references unknown esp service '%s'", m_name.get(), szService);
  97. const char* pszBuild = pService->queryProp("@build");
  98. if (!pszBuild || 0 != strcmp(pszBuild, myBuild))
  99. throw MakeStringException(0, "ESP service '%s' used by ESP process '%s'\n has a different build (%s) to its ESP process!",
  100. szService, m_name.get(), pszBuild);
  101. // Get plugin file list from the plugin process
  102. CDeploymentEngine::determineInstallFiles(*pService, installFiles);
  103. }
  104. int rc = CDeploymentEngine::determineInstallFiles(node, installFiles);
  105. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "");
  106. return rc;
  107. }
  108. //---------------------------------------------------------------------------
  109. // processCustomMethod
  110. //---------------------------------------------------------------------------
  111. void CEspDeploymentEngine::processCustomMethod(const char *method, const char *source, const char *outputFile,
  112. const char *instanceName, EnvMachineOS os)
  113. {
  114. if (!stricmp(method, "ssl_certificate"))
  115. {
  116. //we only need to worry about SSL certificates and private keys if https is being used
  117. //by any of our bindings
  118. //
  119. Owned<IPropertyTreeIterator> it = m_process.getElements("EspBinding[@protocol='https']");
  120. if (!it->first())
  121. return;
  122. }
  123. CDeploymentEngine::processCustomMethod(method, source, outputFile, instanceName, os);
  124. }
  125. //---------------------------------------------------------------------------
  126. // xslTransform
  127. //---------------------------------------------------------------------------
  128. void CEspDeploymentEngine::xslTransform(
  129. const char *xslFilePath, const char *outputFilePath,
  130. const char* instanceName, EnvMachineOS os/*=MachineOsUnknown*/,
  131. const char* processName/*=NULL*/,
  132. bool isEspModuleOrPlugin/*=false*/)
  133. {
  134. m_createIni = false;
  135. // Skip if not processing config files
  136. checkAbort();
  137. if (!m_compare)
  138. ensurePath(outputFilePath);
  139. if (m_compare)
  140. outputFilePath = setCompare(outputFilePath);
  141. if (instanceName)
  142. {
  143. m_transform->setParameter("instance", StringBuffer("'").append(instanceName).append("'").str());
  144. const char* szXslFileName = pathTail(xslFilePath);
  145. if (!stricmp(szXslFileName, "esp.xsl"))
  146. {
  147. //disable compare since these transforms are needed by us in any case for esp.xml
  148. const bool bCompare = m_compare;
  149. m_compare = false;
  150. //we need to pass in a list of file names created as a result of individual esp service modules
  151. //running xslt using method xslt_esp_service on their own service specific XSL files as specified
  152. //in install set (created by release_<service>.bat
  153. //
  154. //esp.xsl merges these in the output under /Environment/Software/EspProcess
  155. //
  156. StringBuffer serviceXsltOutputFiles;
  157. processServiceModules("esp_plugin", serviceXsltOutputFiles, instanceName, os);
  158. processServiceModules("esp_service_module", serviceXsltOutputFiles, instanceName, os);
  159. m_compare = bCompare;
  160. IEnvDeploymentEngine& envDepEngine = getEnvDepEngine();
  161. const char* srcDaliAddress = envDepEngine.getSourceDaliAddress();
  162. m_transform->setParameter("espServiceName", "''");
  163. m_transform->setParameter("serviceFilesList", StringBuffer("'").append(serviceXsltOutputFiles.str()).append("'").str());
  164. m_transform->setParameter("deployedFromDali", StringBuffer("'").append(srcDaliAddress).append("'").str());
  165. }
  166. }
  167. if (m_deployFlags & DEFLAGS_CONFIGFILES) //are we processing config files?
  168. {
  169. Owned<IDeployTask> task =
  170. createDeployTask(*m_pCallback, "XSL Transform", m_process.queryName(), m_name.get(),
  171. instanceName, xslFilePath, outputFilePath, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(),
  172. 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 CEspDeploymentEngine::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 CDeploymentEngine::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. CDeploymentEngine::xslTransform(source, dest.c_str(), instanceName, os, NULL, true);
  235. }
  236. }
  237. }
  238. }