/*############################################################################## Copyright (C) 2011 HPCC Systems. All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . ############################################################################## */ #include "jptree.hpp" #include "jmutex.hpp" #include "jexcept.hpp" #include "environment.hpp" #include "xslprocessor.hpp" #include "espconfiggenengine.hpp" #include #include using std::set; using std::string; //--------------------------------------------------------------------------- // CEspConfigGenEngine //--------------------------------------------------------------------------- CEspConfigGenEngine::CEspConfigGenEngine(IEnvDeploymentEngine& envDepEngine, IDeploymentCallback& callback, IPropertyTree& process, const char* inputDir, const char* outputDir) : CConfigGenEngine(envDepEngine, callback, process, inputDir, outputDir, "./Instance") { } //--------------------------------------------------------------------------- // check //--------------------------------------------------------------------------- void CEspConfigGenEngine::check() { CConfigGenEngine::check(); // Make sure all protocol and service referenced by bindings are valid Owned iter = m_process.getElements("EspBinding"); for (iter->first(); iter->isValid(); iter->next()) { IPropertyTree* pBinding = &iter->query(); const char* service = pBinding->queryProp("@service"); if (service) { if (!lookupProcess("EspService", service)) throw MakeStringException(0, "Process %s references unknown service %s", m_name.get(), service); } else throw MakeStringException(-1, "The ESP binding %s for ESP %s has missing service information!", pBinding->queryProp("@name"), m_name.get()); } // Make sure DaliServers are valid iter.setown(m_process.getElements(".//*[@daliServers]")); ForEach(*iter) { const char* name = iter->query().queryProp("@daliServers"); if (name && *name && !lookupProcess("DaliServerProcess", name)) throw MakeStringException(0, "Process %s references unknown DaliServers %s", m_name.get(), name); } // Make sure EclServer is valid iter.setown(m_process.getElements(".//*[@eclServer]")); ForEach(*iter) { const char* name = iter->query().queryProp("@eclServer"); if (name && *name && !lookupProcess("EclServerProcess", name)) throw MakeStringException(0, "Process %s references unknown EclServer %s", m_name.get(), name); } // Make sure AttributeServer is valid iter.setown(m_process.getElements(".//*[@attributeServer]")); ForEach(*iter) { const char* name = iter->query().queryProp("@attributeServer"); if (name && *name && !lookupProcess("AttrServerProcess", name)) throw MakeStringException(0, "Process %s references unknown AttributeServer %s", m_name.get(), name); } } //--------------------------------------------------------------------------- // createInstallFileMap //--------------------------------------------------------------------------- int CEspConfigGenEngine::determineInstallFiles(IPropertyTree& node, CInstallFiles& installFiles) const { m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Merging file lists for ESP server and its bound service(s) ..."); const char* myBuild = m_process.queryProp("@build"); //process bindings for this esp process and add files for each service used by //each binding before adding files for this esp process Owned iBinding = m_process.getElements("EspBinding"); ForEach(*iBinding) { IPropertyTree* pBinding = &iBinding->query(); const char* szService = pBinding->queryProp("@service"); // Lookup plugin process IPropertyTree* pService = lookupProcess("EspService", szService); if (!pService) throw MakeStringException(0, "Process %s references unknown esp service '%s'", m_name.get(), szService); const char* pszBuild = pService->queryProp("@build"); if (!pszBuild || 0 != strcmp(pszBuild, myBuild)) throw MakeStringException(0, "ESP service '%s' used by ESP process '%s'\n has a different build (%s) to its ESP process!", szService, m_name.get(), pszBuild); // Get plugin file list from the plugin process CConfigGenEngine::determineInstallFiles(*pService, installFiles); } int rc = CConfigGenEngine::determineInstallFiles(node, installFiles); m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "determineInstallFiles complete"); return rc; } //--------------------------------------------------------------------------- // processCustomMethod //--------------------------------------------------------------------------- void CEspConfigGenEngine::processCustomMethod(const char *method, const char *source, const char *outputFile, const char *instanceName, EnvMachineOS os) { if (!stricmp(method, "ssl_certificate")) { //we only need to worry about SSL certificates and private keys if https is being used //by any of our bindings // Owned it = m_process.getElements("EspBinding[@protocol='https']"); if (!it->first()) return; } CConfigGenEngine::processCustomMethod(method, source, outputFile, instanceName, os); } //--------------------------------------------------------------------------- // xslTransform //--------------------------------------------------------------------------- void CEspConfigGenEngine::xslTransform( const char *xslFilePath, const char *outputFilePath, const char* instanceName, EnvMachineOS os/*=MachineOsUnknown*/, const char* processName/*=NULL*/, bool isEspModuleOrPlugin/*=false*/) { m_createIni = false; // Skip if not processing config files checkAbort(); if (!m_compare) ensurePath(outputFilePath); if (m_compare) outputFilePath = setCompare(outputFilePath); if (instanceName) { m_transform->setParameter("instance", StringBuffer("'").append(instanceName).append("'").str()); const char* szXslFileName = pathTail(xslFilePath); if (!stricmp(szXslFileName, "esp.xsl")) { //disable compare since these transforms are needed by us in any case for esp.xml const bool bCompare = m_compare; m_compare = false; //we need to pass in a list of file names created as a result of individual esp service modules //running xslt using method xslt_esp_service on their own service specific XSL files as specified //in install set (created by release_.bat // //esp.xsl merges these in the output under /Environment/Software/EspProcess // StringBuffer serviceXsltOutputFiles; processServiceModules("esp_plugin", serviceXsltOutputFiles, instanceName, os); processServiceModules("esp_service_module", serviceXsltOutputFiles, instanceName, os); m_compare = bCompare; IEnvDeploymentEngine& envDepEngine = getEnvDepEngine(); const char* srcDaliAddress = envDepEngine.getSourceDaliAddress(); m_transform->setParameter("espServiceName", "''"); m_transform->setParameter("serviceFilesList", StringBuffer("'").append(serviceXsltOutputFiles.str()).append("'").str()); m_transform->setParameter("deployedFromDali", StringBuffer("'").append(srcDaliAddress).append("'").str()); } } if (m_deployFlags & DEFLAGS_CONFIGFILES) //are we processing config files? { Owned task = createDeployTask(*m_pCallback, "XSL Transform", m_process.queryName(), m_name.get(), instanceName, xslFilePath, outputFilePath, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os, processName); m_pCallback->printStatus(task); task->transformFile(*m_processor, *m_transform, m_cachePath.get()); m_pCallback->printStatus(task); checkAbort(task); } if (m_compare) compareFiles(os); } void CEspConfigGenEngine::processServiceModules(const char* moduleType, StringBuffer& serviceXsltOutputFiles, const char* instanceName, EnvMachineOS os) { set serviceNamesProcessed; bool bEspServiceModule = !stricmp(moduleType, "esp_service_module"); char tempPath[_MAX_PATH]; getTempPath(tempPath, sizeof(tempPath), m_name); const CInstallFileList& fileList = m_installFiles.getInstallFileList(); CInstallFileList::const_iterator i = fileList.begin(); CInstallFileList::const_iterator iEnd = fileList.end(); for (; i != iEnd; i++) { const CInstallFile& installFile = *(*i); const char* method = installFile.getMethod().c_str(); if (!stricmp(method, moduleType)) { const char* source = installFile.getSrcPath().c_str(); std::string dest = installFile.getDestPath().c_str(); //our base class method CConfigGenEngine::determineInstallFiles() encoded //dest is of the format + so extract both of the parts // std::string::size_type pos = dest.find_last_of('+'); std::string serviceName = dest.substr(pos+1); dest.erase(pos); if ((pos = dest.find("@temp" PATHSEPSTR)) != std::string::npos) dest.replace(pos, strlen("@temp" PATHSEPSTR), tempPath); //if method is esp_service_module then check to see if not processing config files // bool bProcess = true; if (bEspServiceModule) { if (m_deployFlags & DEFLAGS_CONFIGFILES) { //each esp_service_module for a given service name is expected to produce necessary //and sufficient information for itself (EspService node) and all its EspBindings //(we may have multiple bindings for the same service i.e. EspService[@name='xyz']). //Therefore, we only need to process one instance of EspService exactly once. if (serviceNamesProcessed.find(serviceName) != serviceNamesProcessed.end()) continue; serviceNamesProcessed.insert(serviceName); serviceXsltOutputFiles.append(dest.c_str()); serviceXsltOutputFiles.append(';'); } else bProcess = false; } if (bProcess) { serviceName.insert(0, "\'"); serviceName += '\''; m_transform->setParameter("espServiceName", serviceName.c_str()); CConfigGenEngine::xslTransform(source, dest.c_str(), instanceName, os, NULL, true); } } } }