DeploymentEngine.cpp 100 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577
  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. #pragma warning(disable : 4786)
  15. #include <functional>
  16. #include <algorithm>
  17. #include "deploy.hpp"
  18. #include "environment.hpp"
  19. #include "DeploymentEngine.hpp"
  20. #include "jexcept.hpp"
  21. #include "jfile.hpp"
  22. #include "jmisc.hpp"
  23. #include "jptree.hpp"
  24. #include "jmutex.hpp"
  25. #include "xslprocessor.hpp"
  26. #include "securesocket.hpp"
  27. #ifndef _WIN32
  28. #include <unistd.h>
  29. #endif
  30. /*static*/ CInstallFileList CDeploymentEngine::s_dynamicFileList;
  31. /*static*/ CDeploymentEngine* CDeploymentEngine::s_xsltDepEngine = NULL;//deployment engine context for XSLT
  32. /*static*/ bool CDeploymentEngine::s_bCacheableDynFile = false;
  33. //---------------------------------------------------------------------------
  34. // CDeploymentEngine
  35. //---------------------------------------------------------------------------
  36. CDeploymentEngine::CDeploymentEngine(IEnvDeploymentEngine& envDepEngine,
  37. IDeploymentCallback& callback,
  38. IPropertyTree &process,
  39. const char *instanceType,
  40. bool createIni)
  41. : m_envDepEngine(envDepEngine),
  42. m_environment(envDepEngine.getEnvironment()),
  43. m_process(process),
  44. m_instanceType(instanceType),
  45. m_abort(false),
  46. m_startable(unknown),
  47. m_stoppable(unknown),
  48. m_createIni(createIni),
  49. m_curInstance(NULL)
  50. {
  51. m_pCallback.set(&callback);
  52. m_installFiles.setDeploymentEngine(*this);
  53. m_name.set(m_process.queryProp("@name"));
  54. m_rootNode.setown(&m_environment.getPTree());
  55. m_useSSHIfDefined = true;
  56. assertex(m_rootNode);
  57. // Get instances
  58. if (m_instanceType.length()==0)
  59. m_instances.append(OLINK(m_process));
  60. else
  61. {
  62. Owned<IPropertyTreeIterator> iter = m_process.getElements(m_instanceType);
  63. if (!iter->first())
  64. throw MakeStringException(0, "Process %s has no instances defined", m_name.get());
  65. for (iter->first(); iter->isValid(); iter->next())
  66. m_instances.append(iter->get());
  67. }
  68. // Get name to use for INI file - use buildset name
  69. if (m_createIni)
  70. m_iniFile.set(StringBuffer(m_process.queryProp("@buildSet")).append(".ini").str());
  71. }
  72. //---------------------------------------------------------------------------
  73. // ~CDeploymentEngine
  74. //---------------------------------------------------------------------------
  75. CDeploymentEngine::~CDeploymentEngine()
  76. {
  77. // Do disconnects
  78. set<string>::const_iterator iEnd = m_connections.end();
  79. set<string>::const_iterator i;
  80. for (i=m_connections.begin(); i!=iEnd; i++)
  81. {
  82. const char* path = (*i).c_str();
  83. if (!m_envDepEngine.IsPersistentConnection(path))
  84. disconnectHost( path );
  85. }
  86. if (m_externalFunction)
  87. m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction.get(), false);
  88. if (m_externalFunction2)
  89. m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction2.get(), false);
  90. }
  91. //---------------------------------------------------------------------------
  92. // addInstance
  93. //---------------------------------------------------------------------------
  94. void CDeploymentEngine::addInstance(const char* tagName, const char* name)
  95. {
  96. if (m_instanceType.length() == 0)
  97. throw MakeStringException(-1, "%s: Specification of individual instances is not allowed!", m_name.get());
  98. StringBuffer xpath;
  99. xpath.appendf("%s[@name='%s']", tagName, name);
  100. Owned<IPropertyTree> pInstance = m_process.getPropTree(xpath.str());
  101. if (!pInstance)
  102. throw MakeStringException(-1, "%s: Instance '%s' cannot be found!", m_name.get(), name);
  103. m_instances.append(*pInstance.getLink());
  104. }
  105. //---------------------------------------------------------------------------
  106. // getInstallFileCount
  107. //---------------------------------------------------------------------------
  108. // whether a method is trackable for progress stats purpose
  109. static bool isMethodTrackable(const char* method)
  110. {
  111. return strieq(method,"copy") || startsWith(method,"xsl"); //|| strieq(method,"esp_service_module");
  112. }
  113. int CDeploymentEngine::getInstallFileCount()
  114. {
  115. const CInstallFileList& files = getInstallFiles().getInstallFileList();
  116. // debug untrackable files
  117. if (0)
  118. {
  119. StringBuffer s;
  120. for (CInstallFileList::const_iterator it=files.begin(); it!=files.end(); ++it)
  121. {
  122. const StlLinked<CInstallFile>& f = *it;
  123. if (!isMethodTrackable(f->getMethod().c_str()) || startsWith(f->getMethod().c_str(),"xsl"))
  124. s.append(f->getMethod().c_str()).append(": ").append(f->getSrcPath().c_str())
  125. .append(" --> ").append(f->getDestPath().c_str()).newline();
  126. }
  127. Owned<IFile> f = createIFile("c:\\temp\\files.txt");
  128. Owned<IFileIO> fio = f->open(IFOwrite);
  129. fio->write(0,s.length(),s.str());
  130. }
  131. // This includes all files, such as, esp_service_module, esp_plugins and custom
  132. //return getInstallFiles().getInstallFileList().size();
  133. // Only count these we can handle properly
  134. int count = 0;
  135. for (CInstallFileList::const_iterator it=files.begin(); it!=files.end(); ++it)
  136. {
  137. const StlLinked<CInstallFile>& f = *it;
  138. if (isMethodTrackable(f->getMethod().c_str()))
  139. count++;
  140. }
  141. return count;
  142. }
  143. //---------------------------------------------------------------------------
  144. // getInstallFileSize
  145. //---------------------------------------------------------------------------
  146. offset_t CDeploymentEngine::getInstallFileSize()
  147. {
  148. const CInstallFileList& files = getInstallFiles().getInstallFileList();
  149. offset_t totalSize = 0;
  150. for (CInstallFileList::const_iterator it=files.begin(); it!=files.end(); ++it)
  151. {
  152. const StlLinked<CInstallFile>& f = *it;
  153. if (isMethodTrackable(f->getMethod().c_str()))
  154. totalSize += f->getSrcSize();
  155. /* debug
  156. if (f->getSrcSize()==24331)
  157. {
  158. VStringBuffer s("%s : %s -> %s", f->getMethod().c_str(), f->getSrcPath().c_str(), f->getDestPath().c_str());
  159. ::MessageBox((HWND)m_pCallback->getWindowHandle(), s.str(), "UNCOPIED",MB_OK);
  160. }*/
  161. }
  162. return totalSize;
  163. }
  164. //---------------------------------------------------------------------------
  165. // start
  166. //---------------------------------------------------------------------------
  167. void CDeploymentEngine::start()
  168. {
  169. //some components may not have defined startup.bat or stop.bat scripts
  170. //in their installset since those actions may not be relevant (for e.g.
  171. //dfu) so ignore startup/stop commands in that case
  172. checkBuild();
  173. if (m_startable == unknown)
  174. m_startable = searchDeployMap("startup", ".bat") ? yes : no;
  175. if (m_startable == yes)
  176. {
  177. ForEachItemIn(idx, m_instances)
  178. {
  179. checkAbort();
  180. IPropertyTree& instance = m_instances.item(idx);
  181. m_curInstance = instance.queryProp("@name");
  182. m_curSSHUser.clear();
  183. m_curSSHKeyFile.clear();
  184. m_curSSHKeyPassphrase.clear();
  185. m_envDepEngine.getSSHAccountInfo(instance.queryProp("@computer"), m_curSSHUser, m_curSSHKeyFile, m_curSSHKeyPassphrase);
  186. if (m_useSSHIfDefined)
  187. m_useSSHIfDefined = !m_curSSHKeyFile.isEmpty();
  188. try
  189. {
  190. char tempPath[_MAX_PATH];
  191. getTempPath(tempPath, sizeof(tempPath), m_name);
  192. ensurePath(tempPath);
  193. m_envDepEngine.addTempDirectory( tempPath );
  194. startInstance(instance);
  195. }
  196. catch (IException* e)
  197. {
  198. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e))//retry ?
  199. idx--;
  200. }
  201. catch (...)
  202. {
  203. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, NULL))//retry ?
  204. idx--;
  205. }
  206. }//for
  207. m_curInstance = NULL;
  208. }
  209. }
  210. //---------------------------------------------------------------------------
  211. // startInstance
  212. //---------------------------------------------------------------------------
  213. void CDeploymentEngine::startInstance(IPropertyTree& node, const char* fileName/*="startup"*/)
  214. {
  215. EnvMachineOS os = m_envDepEngine.lookupMachineOS(node);
  216. StringAttr hostDir(getHostDir(node).str());
  217. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  218. "Starting %s process on %s", m_name.get(), hostDir.get());
  219. Owned<IDeployTask> task;
  220. if (m_useSSHIfDefined && os == MachineOsLinux && !m_curSSHUser.isEmpty() && !m_curSSHKeyFile.isEmpty())
  221. {
  222. const char* computer = node.queryProp("@computer");
  223. if (!computer || !*computer)
  224. return;
  225. const char* dir = hostDir.sget();
  226. StringBuffer destpath, destip;
  227. stripNetAddr(dir, destpath, destip);
  228. StringBuffer cmd, output, err, destdir;
  229. destdir.append(destpath.length() - 1, destpath.str());
  230. cmd.clear().appendf("%s%s %s", destpath.str(), fileName, destdir.str());
  231. task.set(createDeployTask(*m_pCallback, "Start Instance", m_process.queryName(), m_name.get(), m_curInstance, fileName, dir, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os));
  232. m_pCallback->printStatus(task);
  233. bool flag = task->execSSHCmd(destip.str(), cmd, output, err);
  234. }
  235. else
  236. {
  237. StringBuffer startCmd;
  238. startCmd.append(hostDir).append(fileName);
  239. if (os == MachineOsW2K)
  240. startCmd.append(".bat");
  241. StringAttr user, pwd;
  242. m_envDepEngine.getAccountInfo(node.queryProp("@computer"), user, pwd);
  243. // Spawn start process
  244. connectToHost(node);
  245. task.set(createDeployTask(*m_pCallback, "Start Instance", m_process.queryName(),
  246. m_name.get(), m_curInstance, NULL, startCmd.str(),
  247. m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os));
  248. m_pCallback->printStatus(task);
  249. task->createProcess(true, user, pwd);
  250. }
  251. m_pCallback->printStatus(task);
  252. checkAbort(task);
  253. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  254. }
  255. //---------------------------------------------------------------------------
  256. // stop
  257. //---------------------------------------------------------------------------
  258. void CDeploymentEngine::stop()
  259. {
  260. //some components may not have defined startup.bat or stop.bat scripts
  261. //in their installset since those actions may not be relevant (for e.g.
  262. //dfu) so ignore startup/stop commands in that case
  263. checkBuild();
  264. if (m_stoppable == unknown)
  265. m_stoppable = searchDeployMap("stop", ".bat") ? yes : no;
  266. if (m_stoppable == yes)
  267. {
  268. ForEachItemIn(idx, m_instances)
  269. {
  270. checkAbort();
  271. IPropertyTree& instance = m_instances.item(idx);
  272. m_curInstance = instance.queryProp("@name");
  273. m_curSSHUser.clear();
  274. m_curSSHKeyFile.clear();
  275. m_curSSHKeyPassphrase.clear();
  276. m_envDepEngine.getSSHAccountInfo(instance.queryProp("@computer"), m_curSSHUser, m_curSSHKeyFile, m_curSSHKeyPassphrase);
  277. if (m_useSSHIfDefined)
  278. m_useSSHIfDefined = !m_curSSHKeyFile.isEmpty();
  279. try
  280. {
  281. char tempPath[_MAX_PATH];
  282. getTempPath(tempPath, sizeof(tempPath), m_name);
  283. ensurePath(tempPath);
  284. m_envDepEngine.addTempDirectory( tempPath );
  285. stopInstance(instance);
  286. }
  287. catch (IException* e)
  288. {
  289. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e))//retry ?
  290. idx--;
  291. }
  292. catch (...)
  293. {
  294. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, NULL))//retry ?
  295. idx--;
  296. }
  297. }
  298. m_curInstance = NULL;
  299. }
  300. }
  301. //---------------------------------------------------------------------------
  302. // stopInstance
  303. //---------------------------------------------------------------------------
  304. void CDeploymentEngine::stopInstance(IPropertyTree& node, const char* fileName/*="stop"*/)
  305. {
  306. EnvMachineOS os = m_envDepEngine.lookupMachineOS(node);
  307. StringAttr hostDir(getHostDir(node).str());
  308. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  309. "Stopping %s process on %s", m_name.get(), hostDir.get());
  310. Owned<IDeployTask> task;
  311. if (m_useSSHIfDefined && os == MachineOsLinux && !m_curSSHUser.isEmpty() && !m_curSSHKeyFile.isEmpty())
  312. {
  313. const char* computer = node.queryProp("@computer");
  314. if (!computer || !*computer)
  315. return;
  316. const char* dir = hostDir.sget();
  317. StringBuffer destpath, destip;
  318. stripNetAddr(dir, destpath, destip);
  319. StringBuffer cmd, output, err, destdir;
  320. destdir.append(destpath.length() - 1, destpath.str());
  321. cmd.clear().appendf("%s%s %s", destpath.str(), fileName, destdir.str());
  322. task.set(createDeployTask(*m_pCallback, "Stop Instance", m_process.queryName(), m_name.get(), m_curInstance, fileName, dir, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os));
  323. m_pCallback->printStatus(task);
  324. bool flag = task->execSSHCmd(destip.str(), cmd, output, err);
  325. }
  326. else
  327. {
  328. StringBuffer stopCmd;
  329. StringAttr user, pwd;
  330. stopCmd.append(hostDir).append(fileName);
  331. m_envDepEngine.getAccountInfo(node.queryProp("@computer"), user, pwd);
  332. EnvMachineOS os = m_envDepEngine.lookupMachineOS(node);
  333. if (os == MachineOsW2K)
  334. stopCmd.append(".bat");
  335. // Spawn stop process
  336. connectToHost(node);
  337. task.set(createDeployTask(*m_pCallback, "Stop Instance", m_process.queryName(), m_name.get(),
  338. m_curInstance, NULL, stopCmd.str(), m_curSSHUser.sget(),
  339. m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os));
  340. m_pCallback->printStatus(task);
  341. task->createProcess(true, user, pwd);
  342. }
  343. m_pCallback->printStatus(task);
  344. checkAbort(task);
  345. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  346. }
  347. //---------------------------------------------------------------------------
  348. // check
  349. //---------------------------------------------------------------------------
  350. void CDeploymentEngine::check()
  351. {
  352. checkBuild();
  353. if (m_instances.empty())
  354. throw MakeStringException(0, "Process %s has no instances defined. Nothing to do!", m_name.get());
  355. ForEachItemIn(idx, m_instances)
  356. {
  357. checkAbort();
  358. IPropertyTree& instance = m_instances.item(idx);
  359. m_curInstance = instance.queryProp("@name");
  360. checkInstance(instance);
  361. }
  362. m_curInstance = NULL;
  363. }
  364. //---------------------------------------------------------------------------
  365. // queryDirectory
  366. //---------------------------------------------------------------------------
  367. const char *CDeploymentEngine::queryDirectory(IPropertyTree& node, StringBuffer& sDir) const
  368. {
  369. const char *pszDir = node.queryProp("@directory");
  370. if (!pszDir)
  371. pszDir = m_process.queryProp("@directory");
  372. sDir.clear();
  373. if (pszDir)
  374. sDir.append(pszDir).replace('/', '\\').replace(':', '$'); //make UNC path
  375. return pszDir ? sDir.str() : NULL;
  376. }
  377. //---------------------------------------------------------------------------
  378. // checkInstance
  379. //---------------------------------------------------------------------------
  380. void CDeploymentEngine::checkInstance(IPropertyTree& node) const
  381. {
  382. // Check for valid net address
  383. StringAttr sAttr;
  384. if (m_envDepEngine.lookupNetAddress(sAttr, node.queryProp("@computer")).length()==0)
  385. throw MakeStringException(0, "Process %s has invalid computer net address", m_name.get());
  386. // Check for valid directory
  387. StringBuffer directory;
  388. queryDirectory(node, directory);
  389. if (directory.length()==0)
  390. throw MakeStringException(0, "Process %s has invalid directory", m_name.get());
  391. }
  392. //---------------------------------------------------------------------------
  393. // checkBuild
  394. //---------------------------------------------------------------------------
  395. void CDeploymentEngine::checkBuild() const
  396. {
  397. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  398. "Checking builds for process %s", m_name.get());
  399. // Make sure build and buildset are defined
  400. StringAttr build(m_process.queryProp("@build"));
  401. StringAttr buildset(m_process.queryProp("@buildSet"));
  402. if (build.length()==0 || buildset.length()==0)
  403. throw MakeStringException(0, "Process %s has no build or buildSet defined", m_name.get());
  404. // Make sure build is valid
  405. StringBuffer path;
  406. path.appendf("./Programs/Build[@name=\"%s\"]", build.get());
  407. IPropertyTree* buildNode = m_rootNode->queryPropTree(path.str());
  408. if (!buildNode)
  409. throw MakeStringException(0, "Process %s has invalid build", m_name.get());
  410. // Make sure buildset is valid
  411. path.clear().appendf("./BuildSet[@name=\"%s\"]", buildset.get());
  412. IPropertyTree* buildsetNode = buildNode->queryPropTree(path.str());
  413. if (!buildsetNode)
  414. throw MakeStringException(0, "Process %s has invalid buildSet", m_name.get());
  415. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  416. }
  417. //---------------------------------------------------------------------------
  418. // compare
  419. //---------------------------------------------------------------------------
  420. void CDeploymentEngine::compare(unsigned flags)
  421. {
  422. m_compare = true;
  423. m_deployFlags = flags;
  424. _deploy(false);
  425. }
  426. //---------------------------------------------------------------------------
  427. // deploy
  428. //---------------------------------------------------------------------------
  429. void CDeploymentEngine::deploy(unsigned flags, bool useTempDir)
  430. {
  431. m_compare = false;
  432. m_deployFlags = flags;
  433. _deploy(useTempDir);
  434. }
  435. //---------------------------------------------------------------------------
  436. // beforeDeploy
  437. //---------------------------------------------------------------------------
  438. void CDeploymentEngine::beforeDeploy()
  439. {
  440. m_installFiles.clear();
  441. determineInstallFiles(m_process, m_installFiles);
  442. getCallback().installFileListChanged();
  443. char tempPath[_MAX_PATH];
  444. getTempPath(tempPath, sizeof(tempPath), m_name);
  445. ensurePath(tempPath);
  446. if (m_instances.ordinality() > 1)
  447. {
  448. strcat(tempPath, "Cache");
  449. char* pszEnd = tempPath + strlen(tempPath);
  450. Owned<IFile> pFile = createIFile(tempPath);
  451. int i = 1;
  452. while (pFile->exists()) { //dir/file exists
  453. itoa(++i, pszEnd, 10);
  454. pFile.setown( createIFile(tempPath) );
  455. }
  456. m_envDepEngine.addTempDirectory( tempPath );
  457. strcat(tempPath, PATHSEPSTR);
  458. m_cachePath.set( tempPath );
  459. EnvMachineOS os = m_envDepEngine.lookupMachineOS( m_instances.item(0) );
  460. m_curInstance = "Cache";
  461. copyInstallFiles("Cache", -1, tempPath, os);
  462. }
  463. else
  464. m_cachePath.set( tempPath );
  465. }
  466. //---------------------------------------------------------------------------
  467. // _deploy
  468. //---------------------------------------------------------------------------
  469. void CDeploymentEngine::_deploy(bool useTempDir)
  470. {
  471. m_renameDirList.kill();
  472. beforeDeploy();
  473. m_curSSHUser.clear();
  474. m_curSSHKeyFile.clear();
  475. m_curSSHKeyPassphrase.clear();
  476. ForEachItemIn(idx, m_instances)
  477. {
  478. checkAbort();
  479. IPropertyTree& instanceNode = m_instances.item(idx);
  480. m_curInstance = instanceNode.queryProp("@name");
  481. m_envDepEngine.getSSHAccountInfo(instanceNode.queryProp("@computer"), m_curSSHUser, m_curSSHKeyFile, m_curSSHKeyPassphrase);
  482. if (m_useSSHIfDefined)
  483. m_useSSHIfDefined = !m_curSSHKeyFile.isEmpty();
  484. try
  485. {
  486. deployInstance(instanceNode, useTempDir);
  487. }
  488. catch (IException* e)
  489. {
  490. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e))//retry ?
  491. idx--;
  492. }
  493. catch (...)
  494. {
  495. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, NULL))//retry ?
  496. idx--;
  497. }
  498. }
  499. m_curInstance = NULL;
  500. afterDeploy();
  501. }
  502. //---------------------------------------------------------------------------
  503. // deployInstance
  504. //---------------------------------------------------------------------------
  505. void CDeploymentEngine::deployInstance(IPropertyTree& instanceNode, bool useTempDir)
  506. {
  507. StringAttr hostDir(getHostDir(instanceNode).str());
  508. StringAttr destDir(useTempDir ? getDeployDir(instanceNode).str() : hostDir.get());
  509. const char* pszHostDir = hostDir.get();
  510. if (pszHostDir && *pszHostDir==PATHSEPCHAR && *(pszHostDir+1)==PATHSEPCHAR && m_envDepEngine.lookupMachineOS(instanceNode) != MachineOsLinux)
  511. connectToHost(instanceNode);
  512. beforeDeployInstance(instanceNode, destDir);
  513. copyInstallFiles(instanceNode, destDir);
  514. afterDeployInstance(instanceNode, destDir);
  515. if (!m_compare && useTempDir)
  516. {
  517. checkAbort();
  518. EnvMachineOS os= m_envDepEngine.lookupMachineOS(instanceNode);
  519. renameDir(hostDir, NULL, os);
  520. renameDir(destDir, hostDir, os);
  521. }
  522. }
  523. //---------------------------------------------------------------------------
  524. // renameDirs
  525. //---------------------------------------------------------------------------
  526. void CDeploymentEngine::renameDirs()
  527. {
  528. StringBuffer xpath, err;
  529. bool flag = false;
  530. while (m_renameDirList.length())
  531. {
  532. IDeployTask* task = &m_renameDirList.item(0);
  533. m_pCallback->printStatus(task);
  534. if (task->getMachineOS() == MachineOsLinux && strlen(task->getSSHKeyFile()) && strlen(task->getSSHUser()))
  535. {
  536. StringBuffer fromPath, toPath, err, destip;
  537. const char* source = task->getFileSpec(DT_SOURCE);
  538. stripNetAddr(source, fromPath, destip);
  539. stripNetAddr(task->getFileSpec(DT_TARGET), toPath, destip);
  540. StringBuffer cmd, output;
  541. cmd.clear().appendf("mv %s %s", fromPath.str(), toPath.str());
  542. flag = task->execSSHCmd(destip.str(), cmd, output, err);
  543. }
  544. else
  545. task->renameFile();
  546. m_pCallback->printStatus(task);
  547. checkAbort(task);
  548. m_renameDirList.remove(0);
  549. }
  550. }
  551. //---------------------------------------------------------------------------
  552. // deleteFile
  553. //---------------------------------------------------------------------------
  554. void CDeploymentEngine::deleteFile(const char* target, const char* instanceName, EnvMachineOS os)
  555. {
  556. checkAbort();
  557. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Delete File", m_process.queryName(),
  558. m_name.get(), instanceName, NULL, target, m_curSSHUser.sget(), m_curSSHKeyFile.sget(),
  559. m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os);
  560. task->deleteFile();
  561. //only display status info for successful attempts since some temp files may be attempted to be
  562. //deleted more than one time, for instance, due to multiple esp bindings
  563. if (task->getErrorCode() == 0)
  564. m_pCallback->printStatus(task);
  565. }
  566. //---------------------------------------------------------------------------
  567. // backupDirs
  568. //---------------------------------------------------------------------------
  569. void CDeploymentEngine::backupDirs()
  570. {
  571. ForEachItemIn(idx, m_instances)
  572. {
  573. checkAbort();
  574. IPropertyTree& instance = m_instances.item(idx);
  575. m_curInstance = instance.queryProp("@name");
  576. m_curSSHUser.clear();
  577. m_curSSHKeyFile.clear();
  578. m_curSSHKeyPassphrase.clear();
  579. m_envDepEngine.getSSHAccountInfo(instance.queryProp("@computer"), m_curSSHUser, m_curSSHKeyFile, m_curSSHKeyPassphrase);
  580. m_useSSHIfDefined = !m_curSSHKeyFile.isEmpty();
  581. try
  582. {
  583. EnvMachineOS os = m_envDepEngine.lookupMachineOS(instance);
  584. if (os == MachineOsLinux && !m_curSSHUser.isEmpty() && !m_curSSHKeyFile.isEmpty())
  585. {
  586. StringAttr hostDir(getHostDir(instance).str());
  587. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  588. "Backing up directory %s", hostDir.get());
  589. StringBuffer bkPath;
  590. getBackupDirName(hostDir.sget(), bkPath);
  591. if (bkPath.length() == 0)
  592. return;
  593. StringBuffer fromPath, toPath, err, fromip, toip;
  594. stripNetAddr(hostDir.sget(), fromPath, fromip);
  595. stripNetAddr(bkPath.str(), toPath, toip);
  596. StringBuffer cmd, output;
  597. StringBuffer tmp;
  598. tmp.appendf("%d", msTick());
  599. cmd.clear().appendf("cp -r %s %s", fromPath.str(), toPath.str());
  600. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Backup Directory", m_process.queryName(), m_name.get(),
  601. m_curInstance, fromPath.str(), toPath.str(), m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(),
  602. m_useSSHIfDefined, os);
  603. m_pCallback->printStatus(task);
  604. bool flag = task->execSSHCmd(fromip.str(), cmd, output, err);
  605. m_pCallback->printStatus(task);
  606. checkAbort(task);
  607. }
  608. else
  609. {
  610. connectToHost(instance);
  611. StringAttr hostDir(getHostDir(instance).str());
  612. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  613. "Backing up directory %s", hostDir.get());
  614. backupDir(hostDir);
  615. }
  616. }
  617. catch (IException* e)
  618. {
  619. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e))//retry ?
  620. idx--;
  621. }
  622. catch (...)
  623. {
  624. if (!m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, NULL))//retry ?
  625. idx--;
  626. }
  627. }
  628. m_curInstance = NULL;
  629. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  630. }
  631. //---------------------------------------------------------------------------
  632. // abort
  633. //---------------------------------------------------------------------------
  634. void CDeploymentEngine::abort()
  635. {
  636. m_pCallback->printStatus(STATUS_NORMAL, m_process.queryName(), m_name.get(), m_curInstance, "Aborted!");
  637. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Aborted!");
  638. m_abort = true;
  639. }
  640. //---------------------------------------------------------------------------
  641. // checkAbort
  642. //---------------------------------------------------------------------------
  643. void CDeploymentEngine::checkAbort(IDeployTask* task) const
  644. {
  645. if (m_abort || m_pCallback->getAbortStatus() || (task && task->getAbort()))
  646. throw MakeStringException(0, "User abort");
  647. }
  648. //---------------------------------------------------------------------------
  649. // xslTransform
  650. //---------------------------------------------------------------------------
  651. void CDeploymentEngine::xslTransform(const char *xslFilePath, const char *outputFilePath,
  652. const char* instanceName,
  653. EnvMachineOS os/*=MachineOsUnknown*/,
  654. const char* processName/*=NULL*/,
  655. bool isEspModuleOrPlugin)
  656. {
  657. m_createIni = false;
  658. // Skip if not processing config files
  659. if (!(m_deployFlags & DEFLAGS_CONFIGFILES)) return;
  660. checkAbort();
  661. bool useSSH = true;
  662. if (m_compare)
  663. {
  664. useSSH = false;
  665. outputFilePath = setCompare(outputFilePath);
  666. }
  667. else
  668. ensurePath(outputFilePath);
  669. m_transform->setParameter("processType", StringBuffer("'").append(m_process.queryName()).append("'").str());
  670. s_xsltDepEngine = this; //this is used in external function to get back to deployment engine instance
  671. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "XSL Transform", m_process.queryName(),
  672. m_name.get(), instanceName, xslFilePath, outputFilePath, m_curSSHUser.sget(), m_curSSHKeyFile.sget(),
  673. m_curSSHKeyPassphrase.sget(), useSSH ? m_useSSHIfDefined : useSSH, os, processName);
  674. m_pCallback->printStatus(task);
  675. if (os == MachineOsLinux)
  676. {
  677. char tempPath[_MAX_PATH];
  678. getTempPath(tempPath, sizeof(tempPath), m_name.get());
  679. ensurePath(tempPath);
  680. m_envDepEngine.addTempDirectory( tempPath );
  681. }
  682. task->transformFile(*m_processor, *m_transform, m_cachePath.get());
  683. m_pCallback->printStatus(task);
  684. checkAbort(task);
  685. if (!isEspModuleOrPlugin)
  686. {
  687. try {
  688. Owned<IFile> file = createIFile(xslFilePath);
  689. m_pCallback->fileSizeCopied(file->size(),true);
  690. } catch (...) {
  691. m_pCallback->fileSizeCopied(0,true);
  692. }
  693. }
  694. if (m_compare)
  695. compareFiles(os);
  696. }
  697. //---------------------------------------------------------------------------
  698. // setCompare
  699. //---------------------------------------------------------------------------
  700. const char* CDeploymentEngine::setCompare(const char *filename)
  701. {
  702. assertex(m_compareOld.length()==0 && m_compareNew.length()==0);
  703. m_compareOld.set(filename);
  704. char tempfile[_MAX_PATH];
  705. getTempPath(tempfile, sizeof(tempfile), m_name);
  706. ensurePath(tempfile);
  707. strcat(tempfile, "compare");
  708. // Make sure file name is unique - at least during this session
  709. sprintf(&tempfile[strlen(tempfile)], "%d", m_envDepEngine.incrementTempFileCount());
  710. // Add same extension as filename for use with shell functions
  711. const char* ext = findFileExtension(filename);
  712. if (ext)
  713. strcat(tempfile, ext);
  714. m_envDepEngine.addTempFile(tempfile);
  715. m_compareNew.set(tempfile);
  716. return m_compareNew;
  717. }
  718. //---------------------------------------------------------------------------
  719. // compareFiles
  720. //---------------------------------------------------------------------------
  721. void CDeploymentEngine::compareFiles(EnvMachineOS os)
  722. {
  723. compareFiles(m_compareNew, m_compareOld, os);
  724. //remove(m_compareNew); // let's keep the files around for later compares
  725. m_compareOld.clear();
  726. m_compareNew.clear();
  727. }
  728. //---------------------------------------------------------------------------
  729. // compareFiles
  730. //---------------------------------------------------------------------------
  731. void CDeploymentEngine::compareFiles(const char *newFile, const char *oldFile, EnvMachineOS os)
  732. {
  733. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Compare File",
  734. m_process.queryName(), m_name.get(),
  735. m_curInstance, newFile, oldFile, m_curSSHUser.sget(),
  736. m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os);
  737. m_pCallback->printStatus(task);
  738. task->compareFile(DTC_CRC | DTC_SIZE);
  739. task->setFileSpec(DT_SOURCE, newFile);
  740. m_pCallback->printStatus(task);
  741. checkAbort(task);
  742. }
  743. //---------------------------------------------------------------------------
  744. // writeFile
  745. //---------------------------------------------------------------------------
  746. void CDeploymentEngine::writeFile(const char* filename, const char* str, EnvMachineOS os)
  747. {
  748. // Skip if not processing config files
  749. if (!(m_deployFlags & DEFLAGS_CONFIGFILES)) return;
  750. checkAbort();
  751. bool useSSH = true;
  752. if (m_compare)
  753. {
  754. useSSH = false;
  755. filename = setCompare(filename);
  756. }
  757. else
  758. ensurePath(filename);
  759. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Create File", m_process.queryName(), m_name.get(),
  760. m_curInstance, NULL, filename, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(),
  761. useSSH?m_useSSHIfDefined:useSSH, os);
  762. m_pCallback->printStatus(task);
  763. if (useSSH?m_useSSHIfDefined:useSSH)
  764. {
  765. StringBuffer cmd, output, err, destpath, ip;
  766. stripNetAddr(filename, destpath, ip);
  767. cmd.clear().appendf("echo '%s' > %s; chmod 644 %s", str, destpath.str(), destpath.str());
  768. bool flag = task->execSSHCmd(ip.str(), cmd, output, err);
  769. if (!flag)
  770. {
  771. String errmsg(err.str());
  772. int index = errmsg.indexOf('\n');
  773. String* perr = errmsg.substring(0, index > 0? index : errmsg.length());
  774. output.clear().appendf("%s", perr->toCharArray());
  775. delete perr;
  776. throw MakeStringException(-1, output.str());
  777. }
  778. }
  779. else
  780. task->createFile(str);
  781. m_pCallback->printStatus(task);
  782. checkAbort(task);
  783. if (m_compare) compareFiles(os);
  784. }
  785. //---------------------------------------------------------------------------
  786. // lookupProcess
  787. //---------------------------------------------------------------------------
  788. IPropertyTree *CDeploymentEngine::lookupProcess(const char* type, const char* name) const
  789. {
  790. if (name && *name && type && *type)
  791. {
  792. StringBuffer path;
  793. path.appendf("Software/%s[@name=\"%s\"]", type, name);
  794. Owned<IPropertyTreeIterator> iter = m_rootNode->getElements(path.str());
  795. if (iter->first() && iter->isValid())
  796. {
  797. return &iter->query();
  798. }
  799. }
  800. return NULL;
  801. }
  802. //---------------------------------------------------------------------------
  803. // lookupTable
  804. //---------------------------------------------------------------------------
  805. IPropertyTree* CDeploymentEngine::lookupTable(IPropertyTree* modelTree, const char *table) const
  806. {
  807. StringBuffer xpath;
  808. xpath.appendf("./*[@name='%s']", table);
  809. IPropertyTree *ret = modelTree->queryPropTree(xpath.str());
  810. if (ret)
  811. return ret;
  812. else
  813. throw MakeStringException(0, "Table %s could not be found", table);
  814. }
  815. //---------------------------------------------------------------------------
  816. // getEndPoints
  817. //---------------------------------------------------------------------------
  818. StringBuffer& CDeploymentEngine::getEndPoints(const char* path, const char* delimiter, StringBuffer& endPoints) const
  819. {
  820. Owned<IPropertyTreeIterator> iter = m_rootNode->getElements(path);
  821. for (iter->first(); iter->isValid(); iter->next())
  822. {
  823. Owned<IConstMachineInfo> machine = m_environment.getMachine(iter->query().queryProp("@computer"));
  824. if (machine)
  825. {
  826. if (endPoints.length())
  827. endPoints.append(delimiter);
  828. SCMStringBuffer scmSBuf;
  829. endPoints.append(machine->getNetAddress(scmSBuf).str());
  830. const char* port = iter->query().queryProp("@port");
  831. if (port)
  832. endPoints.append(":").append(port);
  833. }
  834. }
  835. return endPoints;
  836. }
  837. //---------------------------------------------------------------------------
  838. // getDaliServers
  839. //---------------------------------------------------------------------------
  840. StringBuffer& CDeploymentEngine::getDaliServers(StringBuffer& daliServers) const
  841. {
  842. daliServers.clear();
  843. const char* name = m_process.queryProp("@daliServer");
  844. if (!name)
  845. name = m_process.queryProp("@daliServers");
  846. if (name)
  847. {
  848. StringBuffer path;
  849. path.appendf("./Software/DaliServerProcess[@name=\"%s\"]/Instance", name);
  850. getEndPoints(path.str(), ", ", daliServers);
  851. }
  852. return daliServers;
  853. }
  854. //---------------------------------------------------------------------------
  855. // getHostRoot
  856. //---------------------------------------------------------------------------
  857. StringBuffer CDeploymentEngine::getHostRoot(const char* computer, const char* dir, bool bIgnoreDepToFolder/*=false*/) const
  858. {
  859. StringBuffer hostRoot;
  860. StringAttr netAddress;
  861. if (m_envDepEngine.lookupNetAddress(netAddress, computer).length() > 0)
  862. {
  863. const char* depToFolder = m_envDepEngine.getDeployToFolder();
  864. if (depToFolder && !bIgnoreDepToFolder)
  865. hostRoot.append(depToFolder);
  866. else
  867. hostRoot.append(PATHSEPCHAR).append(PATHSEPCHAR);
  868. hostRoot.append(netAddress).append(PATHSEPCHAR);
  869. //for Linux support, allow directories starting with '\' character
  870. if (dir)
  871. {
  872. if (isPathSepChar(*dir))
  873. dir++;
  874. while (*dir && !isPathSepChar(*dir))
  875. hostRoot.append(*dir++);
  876. }
  877. }
  878. return hostRoot;
  879. }
  880. //---------------------------------------------------------------------------
  881. // getHostDir
  882. //---------------------------------------------------------------------------
  883. StringBuffer CDeploymentEngine::getHostDir(IPropertyTree& node, bool bIgnoreDepToFolder/*=false*/)
  884. {
  885. StringBuffer hostDir;
  886. StringAttr netAddress;
  887. if (m_envDepEngine.lookupNetAddress(netAddress, node.queryProp("@computer")).length() > 0)
  888. {
  889. const char* depToFolder = m_envDepEngine.getDeployToFolder();
  890. if (depToFolder && !bIgnoreDepToFolder)
  891. {
  892. hostDir.append(depToFolder);
  893. m_useSSHIfDefined = false;
  894. }
  895. else
  896. hostDir.append(PATHSEPCHAR).append(PATHSEPCHAR);
  897. hostDir.append(netAddress).append(PATHSEPCHAR);
  898. StringBuffer directory;
  899. const char* dir = queryDirectory(node, directory);
  900. //for Linux support, allow directories starting with '\' character
  901. if (dir)
  902. {
  903. if (isPathSepChar(*dir))
  904. dir++;
  905. hostDir.append(dir).append(PATHSEPCHAR);
  906. }
  907. }
  908. return hostDir;
  909. }
  910. //---------------------------------------------------------------------------
  911. // getDeployDir
  912. //---------------------------------------------------------------------------
  913. StringBuffer CDeploymentEngine::getDeployDir(IPropertyTree& node)
  914. {
  915. char deployDir[_MAX_PATH];
  916. strcpy(deployDir, getHostDir(node).str());
  917. removeTrailingPathSepChar(deployDir);
  918. strcat(deployDir, "_deploy" PATHSEPSTR);
  919. return deployDir;
  920. }
  921. //---------------------------------------------------------------------------
  922. // getLocalDir - returns @directory with '$' replaced by ':'
  923. //---------------------------------------------------------------------------
  924. StringBuffer CDeploymentEngine::getLocalDir(IPropertyTree& node) const
  925. {
  926. StringBuffer localDir;
  927. queryDirectory(node, localDir);
  928. if (m_envDepEngine.lookupMachineOS(node) == MachineOsLinux)
  929. {
  930. localDir.replace(':', '$');
  931. localDir.replace('\\', '/');
  932. }
  933. else
  934. {
  935. localDir.replace('$', ':');
  936. localDir.replace('/', '\\');
  937. }
  938. return localDir;
  939. }
  940. //---------------------------------------------------------------------------
  941. // connectToHost
  942. //---------------------------------------------------------------------------
  943. void CDeploymentEngine::connectToHost(IPropertyTree& node, const char* dir/*=NULL*/)
  944. {
  945. const char* computer = node.queryProp("@computer");
  946. StringBuffer directory;
  947. if (!dir)
  948. dir = queryDirectory(node, directory);
  949. StringAttr user;
  950. StringAttr pswd;
  951. m_envDepEngine.getAccountInfo(computer, user, pswd);
  952. connectToNetworkPath( getHostRoot(computer, dir).str(), user, pswd );
  953. }
  954. //---------------------------------------------------------------------------
  955. // static splitUNCPath
  956. //---------------------------------------------------------------------------
  957. bool CDeploymentEngine::stripTrailingDirsFromUNCPath(const char* uncPath, StringBuffer& netPath)
  958. {
  959. const char* p = uncPath;
  960. if (p && *p && isPathSepChar(*p++) && *p && isPathSepChar(*p++))//is it really a network path starting with \\ or //
  961. {
  962. netPath.append(PATHSEPSTR PATHSEPSTR);
  963. //remove trailing directories like dir2, dir3 etc. from paths like \\ip\dir1\dir2\dir3
  964. while (*p && !isPathSepChar(*p))
  965. netPath.append(*p++);
  966. if (*p && isPathSepChar(*p++))
  967. {
  968. netPath.append( PATHSEPCHAR );
  969. if (*p && !isPathSepChar(*p))
  970. {
  971. while (*p && !isPathSepChar(*p))
  972. netPath.append(*p++);
  973. netPath.append( PATHSEPCHAR );
  974. }
  975. return true;
  976. }
  977. }
  978. return false;
  979. }
  980. //---------------------------------------------------------------------------
  981. // connectToHost
  982. //---------------------------------------------------------------------------
  983. void CDeploymentEngine::connectToNetworkPath(const char* uncPath, const char* user, const char* pswd)
  984. {
  985. StringBuffer path;
  986. // make a valid UNC path to connect to and see if we are not already connected
  987. if (!stripTrailingDirsFromUNCPath(uncPath, path) || m_connections.find( path.str() ) != m_connections.end())
  988. return;
  989. if (m_envDepEngine.getDeployToFolder())
  990. m_envDepEngine.getDeployToAccountInfo(user, pswd);
  991. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Connect", m_process.queryName(), m_name.get(),
  992. m_curInstance, NULL, path.str(), "", "", "", false);
  993. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Connecting to %s...", path.str());
  994. m_pCallback->printStatus(task);
  995. task->connectTarget(user, pswd, m_envDepEngine.getInteractiveMode());
  996. m_pCallback->printStatus(task);
  997. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  998. // No sense in continuing if connection falied
  999. if (task->getErrorCode() != 0)
  1000. throw MakeStringException(0, ""); //message already displayed!
  1001. // Save connections for disconnecting during destructor
  1002. m_connections.insert( path.str() );
  1003. }
  1004. //---------------------------------------------------------------------------
  1005. // disconnectHost
  1006. //---------------------------------------------------------------------------
  1007. void CDeploymentEngine::disconnectHost(const char* uncPath)
  1008. {
  1009. // Create log of directory
  1010. IDeployLog* pDeployLog = m_envDepEngine.getDeployLog();
  1011. if (pDeployLog)
  1012. pDeployLog->addDirList(m_name, uncPath);
  1013. // Disconnect
  1014. bool disc = m_pCallback->onDisconnect(uncPath);
  1015. if (disc)
  1016. {
  1017. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Disconnect", m_process.queryName(), m_name.get(),
  1018. m_curInstance, NULL, uncPath, "", "", "", false);
  1019. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Disconnecting from %s...", uncPath);
  1020. m_pCallback->printStatus(task);
  1021. task->disconnectTarget();
  1022. m_pCallback->printStatus(task);
  1023. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  1024. }
  1025. }
  1026. struct string_compare : public std::binary_function<const char*, const char*, bool>
  1027. {
  1028. bool operator()(const char* x, const char* y) const { return stricmp(x, y)==0; }
  1029. };
  1030. //---------------------------------------------------------------------------
  1031. // copyAttributes
  1032. //---------------------------------------------------------------------------
  1033. void CDeploymentEngine::copyAttributes(IPropertyTree *dst, IPropertyTree *src, const char** begin, const char** end)
  1034. {
  1035. Owned<IAttributeIterator> attrs = src->getAttributes();
  1036. for(attrs->first(); attrs->isValid(); attrs->next())
  1037. {
  1038. if(std::find_if(begin, end, std::bind1st(string_compare(), attrs->queryName()+1)) != end)
  1039. dst->addProp(attrs->queryName(), attrs->queryValue());
  1040. }
  1041. }
  1042. //---------------------------------------------------------------------------
  1043. // copyUnknownAttributes
  1044. //---------------------------------------------------------------------------
  1045. void CDeploymentEngine::copyUnknownAttributes(IPropertyTree *dst, IPropertyTree *src, const char** begin, const char** end)
  1046. {
  1047. Owned<IAttributeIterator> attrs = src->getAttributes();
  1048. for(attrs->first(); attrs->isValid(); attrs->next())
  1049. {
  1050. if(std::find_if(begin, end, std::bind1st(string_compare(), attrs->queryName()+1)) == end)
  1051. dst->addProp(attrs->queryName(), attrs->queryValue());
  1052. }
  1053. }
  1054. //---------------------------------------------------------------------------
  1055. // ensurePath
  1056. //---------------------------------------------------------------------------
  1057. void CDeploymentEngine::ensurePath(const char* filespec) const
  1058. {
  1059. // Check if directory already exists
  1060. StringBuffer dir;
  1061. splitDirTail(filespec, dir);
  1062. bool flag = true;
  1063. EnvMachineOS os = MachineOsW2K;
  1064. if (m_curInstance && m_curSSHUser.length() && m_curSSHKeyFile.length())
  1065. {
  1066. StringBuffer xpath, err;
  1067. xpath.appendf("./Instance[@name='%s']", m_curInstance);
  1068. IPropertyTree* pInstanceNode = m_process.queryPropTree(xpath.str());
  1069. if (!pInstanceNode)
  1070. {
  1071. StringBuffer destpath, ip;
  1072. stripNetAddr(dir, destpath, ip);
  1073. if (!ip.length())
  1074. flag = true;
  1075. else
  1076. {
  1077. IConstMachineInfo* pInfo = m_envDepEngine.getEnvironment().getMachineByAddress(ip.str());
  1078. os = pInfo->getOS();
  1079. flag = !checkSSHFileExists(dir);
  1080. }
  1081. }
  1082. else
  1083. {
  1084. os = m_envDepEngine.lookupMachineOS(*pInstanceNode);
  1085. flag = !checkSSHFileExists(dir);
  1086. }
  1087. }
  1088. if (flag)
  1089. {
  1090. Owned<IFile> pIFile = createIFile(dir.str());
  1091. if ((m_curInstance && m_curSSHUser.length() && m_curSSHKeyFile.length()) || !pIFile->exists() || !pIFile->isDirectory())
  1092. {
  1093. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Create Directory", m_process.queryName(), m_name.get(),
  1094. m_curInstance, NULL, dir.str(), m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(),
  1095. m_useSSHIfDefined, os);
  1096. m_pCallback->printStatus(task);
  1097. task->createDirectory();
  1098. m_pCallback->printStatus(task);
  1099. checkAbort(task);
  1100. }
  1101. }
  1102. }
  1103. //---------------------------------------------------------------------------
  1104. // renameDir
  1105. //---------------------------------------------------------------------------
  1106. void CDeploymentEngine::renameDir(const char* from, const char* to, EnvMachineOS os)
  1107. {
  1108. assertex(!m_compare);
  1109. assertex(from && *from);
  1110. // If old path doesn't exist, then nothing to rename
  1111. char oldPath[_MAX_PATH];
  1112. strcpy(oldPath, from);
  1113. removeTrailingPathSepChar(oldPath);
  1114. if (!checkFileExists(oldPath))
  1115. return;
  1116. char newPath[_MAX_PATH];
  1117. if (to && *to)
  1118. {
  1119. // Use destination provided
  1120. assertex(strcmp(from, to) != 0);
  1121. strcpy(newPath, to);
  1122. removeTrailingPathSepChar(newPath);
  1123. }
  1124. else
  1125. {
  1126. // Create new path name with date suffix
  1127. time_t t = time(NULL);
  1128. struct tm* now = localtime(&t);
  1129. sprintf(newPath, "%s_%02d_%02d", oldPath, now->tm_mon + 1, now->tm_mday);
  1130. while (checkFileExists(newPath))
  1131. {
  1132. size32_t end = strlen(newPath) - 1;
  1133. char ch = newPath[end];
  1134. if (ch >= 'a' && ch < 'z')
  1135. newPath[end] = ch + 1;
  1136. else
  1137. strcat(newPath, "a");
  1138. }
  1139. }
  1140. // Save rename task
  1141. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Rename", m_process.queryName(), m_name.get(),
  1142. m_curInstance, oldPath, newPath, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os);
  1143. m_renameDirList.append(*task.getLink());
  1144. }
  1145. //---------------------------------------------------------------------------
  1146. // backupDir
  1147. //---------------------------------------------------------------------------
  1148. void CDeploymentEngine::backupDir(const char* from)
  1149. {
  1150. assertex(from && *from);
  1151. // If from path doesn't exist, then nothing to backup
  1152. char fromPath[_MAX_PATH];
  1153. strcpy(fromPath, from);
  1154. removeTrailingPathSepChar(fromPath);
  1155. if (!checkFileExists(fromPath)) return;
  1156. StringBuffer toPath;
  1157. getBackupDirName(from, toPath);
  1158. // Copy directory
  1159. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Backup Directory", m_process.queryName(), m_name.get(),
  1160. m_curInstance, fromPath, toPath.str(), m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined);
  1161. m_pCallback->printStatus(task);
  1162. task->copyDirectory();
  1163. m_pCallback->printStatus(task);
  1164. checkAbort(task);
  1165. }
  1166. void CDeploymentEngine::getBackupDirName(const char* from, StringBuffer& to)
  1167. {
  1168. // If from path doesn't exist, then nothing to backup
  1169. char fromPath[_MAX_PATH];
  1170. strcpy(fromPath, from);
  1171. removeTrailingPathSepChar(fromPath);
  1172. if (!checkFileExists(fromPath)) return;
  1173. // Create to path name with date suffix
  1174. char toPath[_MAX_PATH];
  1175. time_t t = time(NULL);
  1176. struct tm* now = localtime(&t);
  1177. sprintf(toPath, "%s_%02d_%02d", fromPath, now->tm_mon + 1, now->tm_mday);
  1178. while (checkFileExists(toPath))
  1179. {
  1180. size32_t end = strlen(toPath) - 1;
  1181. char ch = toPath[end];
  1182. if (ch >= 'a' && ch < 'z')
  1183. toPath[end] = ch + 1;
  1184. else
  1185. strcat(toPath, "a");
  1186. }
  1187. to.clear().append(toPath);
  1188. }
  1189. //---------------------------------------------------------------------------
  1190. // copyInstallFiles
  1191. //---------------------------------------------------------------------------
  1192. void CDeploymentEngine::copyInstallFiles(IPropertyTree& instanceNode, const char* destPath)
  1193. {
  1194. EnvMachineOS os = m_envDepEngine.lookupMachineOS(instanceNode);
  1195. int instanceIndex = m_instances.find(instanceNode);
  1196. const char* instanceName = instanceNode.queryProp("@name");
  1197. copyInstallFiles(instanceName, instanceIndex, destPath, os);
  1198. }
  1199. void CDeploymentEngine::copyInstallFiles(const char* instanceName, int instanceIndex, const char* destPath, EnvMachineOS os)
  1200. {
  1201. bool bCacheFiles = instanceIndex == -1 && !strcmp(instanceName, "Cache");
  1202. s_dynamicFileList.clear();
  1203. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  1204. m_compare ? "Comparing install files for %s with %s..." : "Copying install files for %s to %s...",
  1205. m_name.get(), destPath);
  1206. if (m_threadPool == NULL)
  1207. {
  1208. IThreadFactory* pThreadFactory = createDeployTaskThreadFactory();
  1209. m_threadPool.setown(createThreadPool("Deploy Task Thread Pool", pThreadFactory, this, DEPLOY_THREAD_POOL_SIZE));
  1210. pThreadFactory->Release();
  1211. }
  1212. else
  1213. {
  1214. int nThreads = m_threadPool->runningCount();
  1215. if (nThreads > 0)
  1216. throw MakeOsException(-1, "Unfinished threads detected!");
  1217. }
  1218. bool bCompare = m_compare;//save
  1219. try
  1220. {
  1221. m_pCallback->setAbortStatus(false);
  1222. initializeMultiThreadedCopying();
  1223. const CInstallFileList& fileList = m_installFiles.getInstallFileList();
  1224. int nItems = fileList.size();
  1225. int n;
  1226. for (n=0; n<nItems; n++)
  1227. {
  1228. CInstallFile& installFile = *fileList[n];
  1229. const bool bCacheable = installFile.isCacheable();
  1230. if (!bCacheFiles || bCacheable)
  1231. {
  1232. const char* method = installFile.getMethod().c_str();
  1233. const char* source = installFile.getSrcPath().c_str();
  1234. const char* params = installFile.getParams().c_str();
  1235. string dest = installFile.getDestPath().c_str();
  1236. std::string::size_type pos;
  1237. if ((pos = dest.find("@temp" PATHSEPSTR)) != std::string::npos)
  1238. {
  1239. dest.replace(pos, strlen("@temp" PATHSEPSTR), m_cachePath.get());
  1240. //a temp file should not be copied over itself so ignore
  1241. if (!bCacheFiles && !stricmp(source, dest.c_str()))
  1242. continue;
  1243. }
  1244. else
  1245. dest.insert(0, destPath);//note that destPath is always terminated by PATHSEPCHAR
  1246. if (params && !*params)
  1247. params = NULL;
  1248. if (!processInstallFile(m_process, instanceName, method, source, dest.c_str(), os, bCacheable, params))
  1249. break;
  1250. if (bCacheFiles && bCacheable)
  1251. {
  1252. if (0 != stricmp(method, "copy"))
  1253. installFile.setMethod("copy");
  1254. installFile.setSrcPath(dest.c_str());
  1255. m_envDepEngine.addTempFile(dest.c_str());
  1256. }
  1257. }
  1258. }//for
  1259. //now process any dynamically added files (via xslt's external function)
  1260. nItems = s_dynamicFileList.size();
  1261. for (n=0; n<nItems; n++)
  1262. {
  1263. const CInstallFile& installFile = *s_dynamicFileList[n];
  1264. //const bool bCacheable = installFile.isCacheable();
  1265. //if (bCacheable && instanceIndex>0)
  1266. // continue;
  1267. const char* method = installFile.getMethod().c_str();
  1268. //if we are not deploying build files and method is copy then ignore this file
  1269. if (!(m_deployFlags & DEFLAGS_BUILDFILES) && (!method || !stricmp(method, "copy")))
  1270. continue;
  1271. const char* source = installFile.getSrcPath().c_str();
  1272. const char* params = installFile.getParams().c_str();//only supported for dynamically added XSLT files
  1273. bool bCacheable = installFile.isCacheable();
  1274. string dest = installFile.getDestPath();
  1275. StringBuffer src(source);
  1276. if (params && !*params)
  1277. params = NULL;
  1278. if (dest.empty())
  1279. dest += pathTail( installFile.getSrcPath().c_str() );
  1280. //any dynamically generated paths are generated with '\\'
  1281. //In configenv, remote copying takes care of the paths
  1282. //if this is configgen, and we are on linux, replace
  1283. //paths with right separator
  1284. if (PATHSEPCHAR == '/' && os == MachineOsLinux)
  1285. src.replace('\\', '/');
  1286. //resolve conflicts if method is not schema or del
  1287. //find all occurrences of this destination file in the map and resove any conflicts
  1288. //like size mismatch etc.
  1289. bool bAddToFileMap = m_installFiles.resolveConflicts(m_process, method, src.str(), dest.c_str(),
  1290. m_name, m_curInstance, params);
  1291. if (bAddToFileMap)
  1292. {
  1293. CInstallFile* pInstallFileAdded = m_installFiles.addInstallFile(method, src.str(), dest.c_str(), bCacheable, params);
  1294. std::string::size_type pos;
  1295. if ((pos = dest.find("@temp" PATHSEPSTR)) != std::string::npos)
  1296. dest.replace(pos, strlen("@temp" PATHSEPSTR), m_cachePath.get());
  1297. else
  1298. dest.insert(0, destPath);//note that destPath is always terminated by PATHSEPCHAR
  1299. if (!processInstallFile(m_process, instanceName, method, src.str(), dest.c_str(), os, bCacheable, params))
  1300. break;
  1301. if (bCacheFiles && bCacheable)
  1302. {
  1303. if (0 != stricmp(method, "copy"))
  1304. pInstallFileAdded->setMethod("copy");
  1305. pInstallFileAdded->setSrcPath(dest.c_str());
  1306. m_envDepEngine.addTempFile(dest.c_str());
  1307. }
  1308. }
  1309. }//for
  1310. m_threadPool->joinAll();
  1311. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  1312. // if (m_createIni)
  1313. // createIniFile(destPath, os);
  1314. }
  1315. catch (IException* e)
  1316. {
  1317. m_compare = bCompare;
  1318. m_threadPool->joinAll();
  1319. throw e;
  1320. }
  1321. catch (...)
  1322. {
  1323. m_compare = bCompare;
  1324. m_threadPool->joinAll();
  1325. throw MakeErrnoException("Error deploying %s", m_name.get());
  1326. }
  1327. }
  1328. bool CDeploymentEngine::processInstallFile(IPropertyTree& processNode, const char* instanceName,
  1329. const char* method, const char* source, const char* dest,
  1330. EnvMachineOS os, bool bCacheable, const char* params/*=NULL*/)
  1331. {
  1332. while (true)
  1333. {
  1334. try
  1335. {
  1336. checkAbort();
  1337. if (m_pCallback->getAbortStatus())
  1338. return false;
  1339. bool bCompare = m_compare;//save
  1340. //if we are creating a temporary file then disable comparing - deploy
  1341. //since the previously generated temporary file would have been deleted by now
  1342. if (m_compare)
  1343. {
  1344. char tempfile[_MAX_PATH];
  1345. getTempPath(tempfile, sizeof(tempfile), m_name);
  1346. if (!strncmp(dest, tempfile, strlen(tempfile)))
  1347. m_compare = false;
  1348. }
  1349. // Skip if method is copy and we are not copying files
  1350. if (!strnicmp(method, "copy", 4))
  1351. {
  1352. if (m_compare)
  1353. {
  1354. compareFiles(source, dest, os );
  1355. Owned<IFile> f = createIFile(source);
  1356. getCallback().fileSizeCopied(f->size(),true);
  1357. }
  1358. else
  1359. {
  1360. // Copy the file
  1361. ensurePath(dest);
  1362. if (!stricmp(method+4, "_block_until_done")) //copy_block_until_done
  1363. {
  1364. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Copy File", m_process.queryName(), m_name.get(),
  1365. m_curInstance, source, dest, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os);
  1366. task->setFlags(m_deployFlags & DCFLAGS_ALL);
  1367. task->copyFile( m_deployFlags & (DCFLAGS_ALL | DTC_DEL_WRONG_CASE));
  1368. m_pCallback->printStatus(task);
  1369. if (task && task->getAbort())
  1370. throw MakeStringException(0, "User abort");
  1371. }
  1372. else
  1373. {
  1374. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Copy File", m_process.queryName(), m_name.get(),
  1375. m_curInstance, source, dest, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined, os);
  1376. task->setFlags(m_deployFlags & DCFLAGS_ALL);
  1377. m_threadPool->start(task);//start a thread for this task
  1378. }
  1379. }
  1380. }
  1381. else if (!strnicmp(method, "xsl", 3)) //allow xsl, xslt or any other string starting with xsl
  1382. {
  1383. unsigned deployFlags = m_deployFlags;
  1384. if (!strcmp(method, "xslt_deployment"))
  1385. m_deployFlags = deployFlags | DEFLAGS_CONFIGFILES;
  1386. s_bCacheableDynFile = bCacheable;
  1387. xslTransform(source, dest, instanceName, os, params);//params only supported for dynamically added xslt files
  1388. s_bCacheableDynFile = false;
  1389. m_deployFlags = deployFlags;
  1390. }
  1391. else if (!stricmp(method, "esp_service_module")) //processed from CEspDeploymentEngine::xslTransform
  1392. ;
  1393. else if (!stricmp(method, "esp_plugin")) //processed from CEspDeploymentEngine::xslTransform
  1394. ;
  1395. else if (!stricmp(method, "model"))
  1396. {
  1397. //extract name of model from dest file path
  1398. StringBuffer dir;
  1399. const char* pszFileName = splitDirTail(dest, dir);
  1400. const char* pszExtension= strchr(pszFileName, '.');
  1401. if (pszExtension == NULL)
  1402. pszExtension = pszFileName + strlen(pszFileName);
  1403. StringBuffer modelName;
  1404. modelName.append('\'').append(pszExtension - pszFileName, pszFileName).append('\'');
  1405. m_transform->setParameter("modelName", modelName.str());
  1406. xslTransform(source, dest, instanceName, os);
  1407. }
  1408. /* -- unsupported now since this was deemed security hole --
  1409. else if (!stricmp(method, "exec"))
  1410. {
  1411. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Executing %s", dest);
  1412. StringBuffer xpath;
  1413. xpath.appendf("Instance[@name='%s']", instanceName);
  1414. IPropertyTree* pInstanceNode = processNode.queryPropTree(xpath.str());
  1415. StringAttr user, pwd;
  1416. m_envDepEngine.getAccountInfo(pInstanceNode->queryProp("@computer"), user, pwd);
  1417. // Spawn start process
  1418. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Remote Execution", m_name.get(), m_curInstance, NULL, dest, os);
  1419. task->createProcess(true, user, pwd);
  1420. m_pCallback->printStatus(task);
  1421. checkAbort(task);
  1422. }
  1423. else if (!strnicmp(method, "dxsl", 4)) //allow dxsl, dxslt or any other string starting with dxsl
  1424. {
  1425. StringBuffer t(source);
  1426. t.append(".xsl");
  1427. xslTransform(source, t.str(), instanceName, os);
  1428. xslTransform(t.str(), dest, instanceName, os);
  1429. remove(t.str());
  1430. }
  1431. */
  1432. else
  1433. processCustomMethod(method, source, dest, instanceName, os);
  1434. m_compare = bCompare;
  1435. break;
  1436. }
  1437. catch (IException* e)
  1438. {
  1439. if (m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e))//ignore ?
  1440. break;
  1441. }
  1442. catch (...)
  1443. {
  1444. if (m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, NULL))//ignore ?
  1445. break;
  1446. }
  1447. }
  1448. return true;
  1449. }
  1450. //---------------------------------------------------------------------------
  1451. // beforeDeployInstance
  1452. //---------------------------------------------------------------------------
  1453. void CDeploymentEngine::beforeDeployInstance(IPropertyTree& instanceNode, const char* destPath)
  1454. {
  1455. }
  1456. //---------------------------------------------------------------------------
  1457. // checkFileExists
  1458. //---------------------------------------------------------------------------
  1459. bool CDeploymentEngine::checkFileExists(const char* filename) const
  1460. {
  1461. StringBuffer xpath, err;
  1462. bool flag = false;
  1463. xpath.appendf("./Instance[@name='%s']", m_curInstance);
  1464. IPropertyTree* pInstanceNode = m_process.queryPropTree(xpath.str());
  1465. EnvMachineOS os = MachineOsW2K;
  1466. if (!pInstanceNode)
  1467. {
  1468. StringBuffer destpath, ip;
  1469. stripNetAddr(filename, destpath, ip);
  1470. if (ip.length())
  1471. {
  1472. IConstMachineInfo* pInfo = m_envDepEngine.getEnvironment().getMachineByAddress(ip.str());
  1473. os = pInfo->getOS();
  1474. }
  1475. }
  1476. else
  1477. os = m_envDepEngine.lookupMachineOS(*pInstanceNode);
  1478. if (os == MachineOsLinux && m_curSSHUser.length() && m_curSSHKeyFile.length())
  1479. return checkSSHFileExists(filename);
  1480. else
  1481. {
  1482. Owned<IFile> pIFile = createIFile(filename);
  1483. return pIFile->exists();
  1484. }
  1485. }
  1486. //---------------------------------------------------------------------------
  1487. // setXsl
  1488. //---------------------------------------------------------------------------
  1489. void CDeploymentEngine::setXsl(IXslProcessor* processor, IXslTransform* transform)
  1490. {
  1491. m_processor = processor;
  1492. m_transform = transform;
  1493. m_externalFunction.setown(m_transform->createExternalFunction("addDeploymentFile", addDeploymentFile));
  1494. m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction.get(), true);
  1495. m_externalFunction2.setown(m_transform->createExternalFunction("siteCertificate", siteCertificateFunction));
  1496. m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction2.get(), true);
  1497. }
  1498. //---------------------------------------------------------------------------
  1499. // createIniFile
  1500. //---------------------------------------------------------------------------
  1501. void CDeploymentEngine::createIniFile(const char* destPath, EnvMachineOS os)
  1502. {
  1503. // Check if INI file needs to be created
  1504. if (m_iniFile.length() == 0) return;
  1505. // Output all attributes - except certain ones
  1506. const char* ignore[] = {"name", "description", "build", "buildSet" };
  1507. const char** begin = &ignore[0];
  1508. const char** end = &ignore[sizeof(ignore)/sizeof(*ignore)];
  1509. StringBuffer str;
  1510. str.append("# INI file generated by CDeploymentEngine\n\n");
  1511. Owned<IAttributeIterator> aiter = m_process.getAttributes();
  1512. for (aiter->first(); aiter->isValid(); aiter->next())
  1513. {
  1514. // Only output attribute if its value is non-blank
  1515. const char* name = &aiter->queryName()[1];
  1516. const char* val = aiter->queryValue();
  1517. if (val && *val)
  1518. {
  1519. if (std::find_if(begin, end, std::bind1st(string_compare(), name)) == end)
  1520. {
  1521. str.appendf("%s=%s\n", name, val);
  1522. }
  1523. }
  1524. }
  1525. writeFile(StringBuffer(destPath).append(m_iniFile).str(), str.str(), os);
  1526. }
  1527. //---------------------------------------------------------------------------
  1528. // getBuildSetNode
  1529. //---------------------------------------------------------------------------
  1530. IPropertyTree* CDeploymentEngine::queryBuildSetNode(IPropertyTree& processNode,
  1531. IPropertyTree*& buildNode) const
  1532. {
  1533. // Get build node for process
  1534. StringBuffer xpath("Programs/Build[@name='");
  1535. xpath.appendf("%s']", processNode.queryProp("@build"));
  1536. buildNode = m_rootNode->queryPropTree(xpath.str());
  1537. assertex(buildNode);
  1538. // Get buildSet node for process
  1539. xpath.clear();
  1540. xpath.appendf("BuildSet[@name=\"%s\"]", processNode.queryProp("@buildSet"));
  1541. IPropertyTree* buildSetNode = buildNode->queryPropTree(xpath.str());
  1542. assertex(buildSetNode);
  1543. return buildSetNode;
  1544. }
  1545. IPropertyTree* CDeploymentEngine::getDeployMapNode(IPropertyTree* buildNode, IPropertyTree* buildSetNode) const
  1546. {
  1547. // Get some useful attributes
  1548. const char* url = buildNode->queryProp("@url");
  1549. const char* path = buildSetNode->queryProp("@path");
  1550. const char* installSet = buildSetNode->queryProp("@installSet");
  1551. // Workout name for deploy map file
  1552. StringBuffer deployFile(url);
  1553. if (path && *path)
  1554. deployFile.append(PATHSEPCHAR).append(path);
  1555. if (installSet && *installSet)
  1556. deployFile.append(PATHSEPCHAR).append(installSet);
  1557. else
  1558. deployFile.append("\\deploy_map.xml");
  1559. // Read in deploy map file and process file elements
  1560. IPropertyTree* deployNode = createPTreeFromXMLFile(deployFile.str(), ipt_caseInsensitive);
  1561. assertex(deployNode);
  1562. return deployNode;
  1563. }
  1564. bool CDeploymentEngine::searchDeployMap(const char* fileName, const char* optionalFileExt) const
  1565. {
  1566. IPropertyTree* buildNode;
  1567. IPropertyTree* buildSetNode = queryBuildSetNode(m_process, buildNode);
  1568. Owned<IPropertyTree> deployNode = getDeployMapNode(buildNode, buildSetNode);
  1569. StringBuffer xpath;
  1570. xpath.appendf("File[@name='%s']", fileName);
  1571. bool bFound = false;
  1572. Owned<IPropertyTreeIterator> iter = deployNode->getElements(xpath.str());
  1573. if (iter->first() && iter->isValid())
  1574. bFound = true;
  1575. else
  1576. {
  1577. xpath.clear().appendf("File[@name='%s%s']", fileName, optionalFileExt);
  1578. iter.setown( deployNode->getElements(xpath.str()) );
  1579. if (iter->first() && iter->isValid())
  1580. bFound = true;
  1581. }
  1582. return bFound;
  1583. }
  1584. //---------------------------------------------------------------------------
  1585. // determineInstallFiles
  1586. //---------------------------------------------------------------------------
  1587. int CDeploymentEngine::determineInstallFiles(IPropertyTree& processNode, CInstallFiles& installFiles) const
  1588. {
  1589. try
  1590. {
  1591. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL,
  1592. "Determining files to install for %s", processNode.queryProp("@name"));
  1593. IPropertyTree* buildNode;
  1594. IPropertyTree* buildSetNode = queryBuildSetNode(processNode, buildNode);
  1595. Owned<IPropertyTree> deployNode = getDeployMapNode(buildNode, buildSetNode);
  1596. StringBuffer srcFilePath;
  1597. srcFilePath.ensureCapacity(_MAX_PATH);
  1598. const char* url = buildNode->queryProp("@url");
  1599. const char* path = buildSetNode->queryProp("@path");
  1600. const bool bFindStartable = &m_process == &processNode && m_startable == unknown;
  1601. const bool bFindStoppable = &m_process == &processNode && m_stoppable == unknown;
  1602. Owned<IPropertyTreeIterator> iter = deployNode->getElements("File");
  1603. ForEach(*iter)
  1604. {
  1605. IPropertyTree* pFile = &iter->query();
  1606. // Get some useful attributes
  1607. const char* name = pFile->queryProp("@name");
  1608. //if this file is an installset (deploy_map.xml) then ignore it (don't deploy)
  1609. //
  1610. if (!stricmp(name, "deploy_map.xml"))
  1611. continue;
  1612. if (bFindStartable && !strnicmp(name, "startup", sizeof("startup")-1))
  1613. m_startable = yes;
  1614. if (bFindStoppable && !strnicmp(name, "stop", sizeof("stop")-1))
  1615. m_stoppable = yes;
  1616. const char* method = pFile->queryProp("@method");
  1617. if (method && !stricmp(method, "schema"))
  1618. continue;// ignore - could validate against it if we felt brave!
  1619. //if we are not deploying build files and method is copy then ignore this file
  1620. if (!(m_deployFlags & DEFLAGS_BUILDFILES) && (!method || !stricmp(method, "copy")))
  1621. continue;
  1622. const char* srcPath = pFile->queryProp("@srcPath");
  1623. const char* destPath= pFile->queryProp("@destPath");
  1624. const char* destName= pFile->queryProp("@destName");
  1625. bool bCacheable = pFile->getPropBool("@cache", false);
  1626. // Get source filespec
  1627. if (srcPath && !strcmp(srcPath, "@temp"))
  1628. {
  1629. char tempfile[_MAX_PATH];
  1630. getTempPath(tempfile, sizeof(tempfile), m_name);
  1631. srcFilePath.clear().append(tempfile).append(name);
  1632. }
  1633. else
  1634. {
  1635. srcFilePath.clear().append(url).append(PATHSEPCHAR);
  1636. if (path && *path)
  1637. srcFilePath.append(path).append(PATHSEPCHAR);
  1638. if (srcPath && 0!=strcmp(srcPath, "."))
  1639. {
  1640. if (!strncmp(srcPath, "..", 2) && (*(srcPath+2)=='/' || *(srcPath+2)=='\\'))
  1641. {
  1642. StringBuffer reldir(srcPath);
  1643. reldir.replace('/', '\\');
  1644. while (!strncmp(reldir.str(), "..\\", 3))
  1645. {
  1646. srcFilePath.setLength( srcFilePath.length() - 1 ); //remove last char PATHSEPCHAR
  1647. const char* tail = pathTail(srcFilePath.str());
  1648. srcFilePath.setLength( tail - srcFilePath.str() );
  1649. reldir.remove(0, 3);
  1650. }
  1651. srcFilePath.append(reldir).append(PATHSEPCHAR);
  1652. }
  1653. else
  1654. srcFilePath.append(srcPath).append(PATHSEPCHAR);
  1655. }
  1656. srcFilePath.append(name);
  1657. }
  1658. std::string sDestName;
  1659. if (method && (!stricmp(method, "esp_service_module") || !stricmp(method, "esp_plugin")))
  1660. {
  1661. //if this is xsl transformation and we are not generating config files then ignore
  1662. //
  1663. if (!(m_deployFlags & DEFLAGS_CONFIGFILES) && !stricmp(method, "esp_service_module"))
  1664. continue;
  1665. //if this file is an esp service module, encode name of service in the dest file name
  1666. //so the esp deployment can figure out which service this file belongs to
  1667. //
  1668. const char* serviceName = processNode.queryProp("@name");
  1669. //if destination name is specified then use it otherwise use <service-name>[index of module].xml
  1670. sDestName = serviceName;
  1671. if (destName)
  1672. {
  1673. sDestName += '_';
  1674. sDestName += destName;
  1675. }
  1676. else
  1677. {
  1678. int espServiceModules = m_envDepEngine.incrementEspModuleCount();
  1679. if (espServiceModules > 1)
  1680. {
  1681. char achNum[16];
  1682. itoa(espServiceModules, achNum, 10);
  1683. sDestName += achNum;
  1684. }
  1685. sDestName += ".xml";
  1686. }
  1687. //encode name of service herein - this is needed by and removed by CEspDeploymentEngine::processServiceModules()
  1688. sDestName += '+';
  1689. sDestName += processNode.queryProp("@name");//encode the name of service
  1690. }
  1691. else if (method && (!stricmp(method, "xsl") || !stricmp(method, "xslt")) && !(m_deployFlags & DEFLAGS_CONFIGFILES))
  1692. continue;//ignore xsl transformations if we are not generating config files
  1693. else
  1694. {
  1695. if (!method || !*method)
  1696. method = "copy";
  1697. // Get destination filespec
  1698. if (destName && *destName)
  1699. {
  1700. //we now support attribute names within the destination file names like delimted by @ and + (optional)
  1701. //for e.g. segment_@attrib1+_file_@attrib2 would produce segment_attribval1_file_attrib2value
  1702. //+ not necessary if the attribute name ends with the word, for e.g. file_@attrib1
  1703. //for instnace, suite_@eclServer+.bat would expand to suite_myeclserver.bat
  1704. //if this process has an @eclServer with value "myeclserver"
  1705. //
  1706. if (strchr(destName, '@') || strchr(destName, '+'))
  1707. {
  1708. char* pszParts = strdup(destName);
  1709. char *saveptr;
  1710. const char* pszPart = strtok_r(pszParts, "+", &saveptr);
  1711. while (pszPart)
  1712. {
  1713. const char* p = pszPart;
  1714. if (*p)
  1715. {
  1716. if (strchr(p, '@'))//xpath for an attribute?
  1717. {
  1718. // find name of attribute and replace it with its value
  1719. const char* value = m_process.queryProp( p );
  1720. if (value)
  1721. sDestName.append(value);
  1722. }
  1723. else
  1724. sDestName.append(p); //no attribute so copy verbatim
  1725. }
  1726. pszPart = strtok_r(NULL, "+", &saveptr);
  1727. }
  1728. free(pszParts);
  1729. }
  1730. else
  1731. sDestName = destName;
  1732. if (sDestName.empty())
  1733. throw MakeStringException(-1, "The destination file name '%s' for source file '%s' "
  1734. "translates to an empty string!", destName, name);
  1735. }
  1736. }
  1737. StringBuffer destFilePath;
  1738. destFilePath.ensureCapacity(_MAX_PATH);
  1739. bool bTempFile = (destPath && !stricmp(destPath, "@temp")) ||
  1740. !strnicmp(name, "@temp", 5); //@name starts with @temp or @tmp
  1741. if (bTempFile)
  1742. {
  1743. if (sDestName.empty())//dest name not specified
  1744. {
  1745. if (!strcmp(method, "copy"))
  1746. sDestName = name;
  1747. else
  1748. {
  1749. StringBuffer dir;
  1750. const char* pszFileName = splitDirTail(name, dir);
  1751. const char* pExt = findFileExtension(pszFileName);
  1752. if (pExt)
  1753. sDestName.append(pszFileName, pExt-pszFileName);
  1754. else
  1755. sDestName.append(pszFileName);
  1756. char index[16];
  1757. itoa(m_envDepEngine.incrementTempFileCount(), index, 10);
  1758. sDestName.append(index);
  1759. if (pExt)
  1760. sDestName.append(pExt);
  1761. }
  1762. }
  1763. destFilePath.append("@temp" PATHSEPSTR);
  1764. }
  1765. else
  1766. {
  1767. if (destPath && *destPath)
  1768. {
  1769. destFilePath.append(destPath);
  1770. if (destPath[strlen(destPath)-1] != PATHSEPCHAR)
  1771. destFilePath.append(PATHSEPCHAR);
  1772. }
  1773. if (sDestName.empty())
  1774. sDestName = name;
  1775. }
  1776. destFilePath.append(sDestName.c_str());
  1777. //find all occurrences of this destination file in the map and resove any conflicts
  1778. //like size mismatch etc.
  1779. bool bAddToFileMap = installFiles.resolveConflicts(processNode, method, srcFilePath.str(), destFilePath.str(),
  1780. m_name, m_curInstance, NULL);
  1781. //resolve conflicts if method is not schema or exec
  1782. if (0 != stricmp(method, "schema") && 0 != stricmp(method, "exec") && 0 != strnicmp(method, "del", 3))
  1783. {
  1784. }
  1785. else if (!strnicmp(method, "del", 3))//treat files to be deleted as temp files - to be deleted AFTER we are done!
  1786. {
  1787. bTempFile = true;
  1788. bAddToFileMap = false;
  1789. m_envDepEngine.addTempFile(destFilePath.str());
  1790. }
  1791. if (bAddToFileMap)
  1792. {
  1793. if (bTempFile)
  1794. m_envDepEngine.addTempFile(destFilePath.str());
  1795. //enable caching for files to be copied unless expressly asked not to do so
  1796. //
  1797. if (!bCacheable && !strcmp(method, "copy"))
  1798. bCacheable = pFile->getPropBool("@cache", true);
  1799. installFiles.addInstallFile(method, srcFilePath.str(), destFilePath.str(), bCacheable, NULL);
  1800. }
  1801. }
  1802. }
  1803. catch (IException* e)
  1804. {
  1805. StringBuffer msg;
  1806. e->errorMessage(msg);
  1807. e->Release();
  1808. throw MakeStringException(0, "Error creating file list for process %s: %s", m_name.get(), msg.str());
  1809. }
  1810. catch (...)
  1811. {
  1812. throw MakeErrnoException("Error creating file list for process %s", m_name.get());
  1813. }
  1814. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, NULL);
  1815. return installFiles.getInstallFileList().size();
  1816. }
  1817. //---------------------------------------------------------------------------
  1818. // resolveConflicts
  1819. //---------------------------------------------------------------------------
  1820. bool CInstallFileMap::resolveConflicts(IPropertyTree& processNode, const char* method, const char* srcPath,
  1821. const char* destPath, const char* compName,
  1822. const char* instanceName, const char* params)
  1823. {
  1824. bool rc = true;//no unresolved conflicts so add to file map
  1825. //DBGLOG("Resolving conflicts for %s from %s\n", srcPath, destPath);
  1826. //resolve conflicts if method is not schema or del
  1827. if (0 != stricmp(method, "schema") && 0 != stricmp(method, "del"))
  1828. {
  1829. //find all occurrences of this destination file in the map and resove any conflicts
  1830. //like size mismatch etc.
  1831. const_iterator iLower = lower_bound(destPath);
  1832. const_iterator iUpper = upper_bound(destPath);
  1833. offset_t srcSz = 0;
  1834. unsigned srcCRC;
  1835. for (const_iterator it=iLower; it != iUpper; it++)
  1836. {
  1837. rc = false;//don't add to file map
  1838. CInstallFile* pInstallFile = (*it).second;
  1839. const char* method2 = pInstallFile->getMethod().c_str();
  1840. const char* srcPath2= pInstallFile->getSrcPath().c_str();
  1841. const char* params2 = pInstallFile->getParams().c_str();
  1842. //if file at destPath is being generated using same method and src file
  1843. //anyway then don't warn - just don't add to file map
  1844. //
  1845. if ((!stricmp(method, method2) && !stricmp(srcPath, srcPath2)) || pInstallFile->isDuplicateSrcFile(srcPath))
  1846. {
  1847. //if method is xslt and params are different, then add to file map
  1848. if (!stricmp(method, "xslt") && ((params == NULL && params2!= NULL) ||
  1849. (params != NULL && params2 == NULL) ||
  1850. (0 != stricmp(params, params2))))
  1851. rc = true;
  1852. break;
  1853. }
  1854. bool rc2=true;
  1855. if (srcSz == 0)
  1856. {
  1857. try
  1858. {
  1859. srcCRC = getFileCRC(srcPath);
  1860. srcSz = filesize(srcPath);
  1861. }
  1862. catch(IException* e)
  1863. {
  1864. rc2 = false;
  1865. StringBuffer msg;
  1866. e->errorMessage(msg);
  1867. m_pDepEngine->getCallback().printStatus(STATUS_WARN, processNode.queryName(),
  1868. processNode.queryProp("@name"), instanceName, msg.str());
  1869. }
  1870. }
  1871. offset_t srcSz2;
  1872. unsigned srcCRC2;
  1873. if (rc2)
  1874. {
  1875. try {
  1876. srcSz2 = pInstallFile->getSrcSize();
  1877. srcCRC2 = pInstallFile->getSrcCRC();;
  1878. } catch(IException* e) {
  1879. rc2 = false;
  1880. StringBuffer msg;
  1881. e->errorMessage(msg);
  1882. m_pDepEngine->getCallback().printStatus(STATUS_WARN, processNode.queryName(),
  1883. processNode.queryProp("@name"), instanceName, msg.str());
  1884. }
  1885. }
  1886. if (rc2)
  1887. {
  1888. if (srcSz == srcSz2 && srcCRC == srcCRC2)
  1889. pInstallFile->addDuplicateSrcFile( srcPath );
  1890. else
  1891. {
  1892. //for starters, just display an error on every conflict even if this is a
  1893. //redeployment of the same file
  1894. //
  1895. const char* fileName = pathTail(destPath);
  1896. if (!fileName)
  1897. fileName = destPath;
  1898. StringBuffer path1;
  1899. const char* srcFileName1 = splitDirTail(srcPath, path1);
  1900. if (0 != strcmp(srcFileName1, fileName))//src file name is not same as dest file name
  1901. path1.clear().append(srcPath);
  1902. else
  1903. path1.remove( path1.length()-1, 1);
  1904. StringBuffer path2;
  1905. const char* srcFileName2 = splitDirTail(srcPath2, path2);
  1906. if (0 != strcmp(srcFileName2, fileName))//src file name is not same as dest file name
  1907. path2.clear().append(srcPath2);
  1908. else
  1909. path2.remove( path2.length()-1, 1);
  1910. bool bDiffMethods = 0 != strcmp(method, method2);
  1911. StringBuffer msg;
  1912. msg.appendf("File skipped: The file %s to be deployed from %s ", fileName, path1.str());
  1913. if (bDiffMethods)
  1914. msg.appendf("by method '%s' ", method);
  1915. msg.appendf("conflicts with another file from %s", path2.str());
  1916. if (bDiffMethods)
  1917. msg.appendf(" using method '%s'", method2);
  1918. msg.append('.');
  1919. m_pDepEngine->getCallback().printStatus(STATUS_WARN, processNode.queryName(),
  1920. processNode.queryProp("@name"), instanceName,
  1921. msg.str());
  1922. }
  1923. break;
  1924. }
  1925. }
  1926. }
  1927. return rc;
  1928. }
  1929. //---------------------------------------------------------------------------
  1930. // addDeploymentFile
  1931. //---------------------------------------------------------------------------
  1932. /*static*/
  1933. void CDeploymentEngine::addDeploymentFile(StringBuffer &ret, const char *in, IXslTransform*)
  1934. {
  1935. //input is of the format <method>+<file name>+<source dir>+<dest filename>[+<dest subdir>]
  1936. StringArray tokens;
  1937. DelimToStringArray(in, tokens, "+");
  1938. int len = tokens.length();
  1939. if (len < 4)
  1940. throw MakeStringException(0, "Invalid format for external function parameter!");
  1941. const char* method = tokens.item(0);
  1942. const char* name = tokens.item(1);
  1943. const char* srcPath = tokens.item(2);
  1944. const char* destName= tokens.item(3);
  1945. StringBuffer srcPath2(srcPath);
  1946. srcPath2.append(name);
  1947. StringBuffer destPath;
  1948. if (len > 4)
  1949. destPath.append(tokens.item(4));
  1950. destPath.append(destName);
  1951. Owned<CInstallFile> pInstallFile = new CInstallFile(method, srcPath2.str(), destPath.str(), s_bCacheableDynFile);
  1952. if (len > 5)
  1953. pInstallFile->setParams(tokens.item(5));
  1954. s_dynamicFileList.push_back(StlLinkedFilePtr(pInstallFile.get()));
  1955. }
  1956. //---------------------------------------------------------------------------
  1957. // siteCertificate
  1958. //---------------------------------------------------------------------------
  1959. /*static*/
  1960. void CDeploymentEngine::siteCertificateFunction(StringBuffer &ret, const char *in, IXslTransform*)
  1961. {
  1962. //input is of the format <processType>+<process name>+<instance name>+<output path>
  1963. StringArray tokens;
  1964. DelimToStringArray(in, tokens, "+");
  1965. int len = tokens.length();
  1966. if (len < 4)
  1967. throw MakeStringException(0, "Invalid format for external function parameter!");
  1968. const char* processType = tokens.item(0);
  1969. const char* processName = tokens.item(1);
  1970. const char* instanceName= tokens.item(2);
  1971. const char* outputFile = tokens.item(3);
  1972. if (!processType || !*processType || !processName || !*processName ||
  1973. !instanceName || !*instanceName || !outputFile || !*outputFile)
  1974. {
  1975. throw MakeStringException(0, "Invalid parameters for siteCertificate method call!");
  1976. }
  1977. IPropertyTree* pProcess = s_xsltDepEngine->lookupProcess(processType, processName);
  1978. if (!pProcess)
  1979. throw MakeStringException(0, "%s with name %s is not defined!", processType, processName);
  1980. s_xsltDepEngine->siteCertificate( *pProcess, instanceName, outputFile );
  1981. }
  1982. //---------------------------------------------------------------------------
  1983. // processCustomMethod
  1984. //---------------------------------------------------------------------------
  1985. void CDeploymentEngine::processCustomMethod(const char* method, const char *source, const char *outputFile,
  1986. const char *instanceName, EnvMachineOS os)
  1987. {
  1988. //we only recognize ssl_certificate as the custom method so if any other method is sought
  1989. //then throw exception
  1990. StringBuffer dir;
  1991. const char* fileName = splitDirTail(source, dir);
  1992. if (0 != stricmp(method, "ssl_certificate"))
  1993. throw MakeStringException(0, "Process '%s': invalid method '%s' specified for file '%s'",
  1994. m_name.get(), method, fileName);
  1995. siteCertificate(m_process, instanceName, outputFile);
  1996. }
  1997. //---------------------------------------------------------------------------
  1998. // processCustomMethod
  1999. //---------------------------------------------------------------------------
  2000. void CDeploymentEngine::siteCertificate(IPropertyTree& process, const char *instanceName, const char *outputFile)
  2001. {
  2002. const char* pszCertFile;
  2003. const char* pszPrivFile;
  2004. StringBuffer sPrivKey;
  2005. StringBuffer sCertificate;
  2006. bool rc;
  2007. Owned<IDeployTask> task = createDeployTask( *m_pCallback, "Site Certificate", process.queryName(),
  2008. m_name.get(), m_curInstance, NULL, NULL, "", "", "", false);
  2009. m_pCallback->printStatus(task);
  2010. task->setProcessed();
  2011. while (true)
  2012. {
  2013. try
  2014. {
  2015. //generate SSL certificate and private key, if they have not already been generated
  2016. //and save them in the environment under the instance nodes. Note that if the
  2017. //environment is read-only then these are not written out and are lost after close.
  2018. //
  2019. //todo: mark env modified so it gets saved!
  2020. //
  2021. StringBuffer xpath;
  2022. xpath.appendf("Instance[@name='%s']", instanceName);
  2023. IPropertyTree* pInstanceNode = process.queryPropTree(xpath.str());
  2024. IPropertyTree* pHttps = process.queryPropTree("HTTPS");
  2025. if (!pHttps)
  2026. {
  2027. if (!strcmp(process.queryName(), "EspProcess"))
  2028. throw MakeStringExceptionDirect(-1, "Cannot generate SSL certificate.\nNo HTTPS information was specified.");
  2029. else
  2030. pHttps = &process;
  2031. }
  2032. pszCertFile = pHttps->queryProp("@certificateFileName");
  2033. pszPrivFile = pHttps->queryProp("@privateKeyFileName");
  2034. if (!pszCertFile || !*pszCertFile || !pszPrivFile || !*pszPrivFile)
  2035. throw MakeStringExceptionDirect(-1, "Cannot generate SSL certificate.\nName for certificate or private key file was not specified.");
  2036. IPropertyTree* pCertNode = pInstanceNode->queryPropTree("Certificate");
  2037. if (!pCertNode)
  2038. pCertNode = pInstanceNode->addPropTree("Certificate", createPTree());
  2039. else
  2040. sCertificate.append( pCertNode->queryProp(NULL) );
  2041. IPropertyTree* pPrivKeyNode = pInstanceNode->queryPropTree("PrivateKey" );
  2042. if (!pPrivKeyNode)
  2043. pPrivKeyNode = pInstanceNode->addPropTree("PrivateKey", createPTree());
  2044. else
  2045. sPrivKey.append( pPrivKeyNode->queryProp(NULL) );
  2046. IPropertyTree* pCsrNode = pInstanceNode->queryPropTree("CSR" );
  2047. StringBuffer sCSR;
  2048. if (!pCsrNode)
  2049. pCsrNode = pInstanceNode->addPropTree("CSR", createPTree());
  2050. else
  2051. sCSR.append( pCsrNode->queryProp(NULL) );
  2052. bool bRegenerateCSR = pHttps->getPropBool("@regenerateCredentials", false);
  2053. if (sCertificate.length()==0 || sPrivKey.length()==0 || sCSR.length()==0 || bRegenerateCSR)
  2054. {
  2055. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Generating SSL certificate and private key files ...");
  2056. const char* pszOrgUnit = pHttps->queryProp("@organizationalUnit");
  2057. const char* pszOrg = pHttps->queryProp("@organization");
  2058. const char* pszCity = pHttps->queryProp("@city");
  2059. const char* pszState = pHttps->queryProp("@state");
  2060. const char* pszCountry = pHttps->queryProp("@country");
  2061. const char* pszPassPhrase= pHttps->queryProp("@passphrase");
  2062. const char* pszFQDN = pInstanceNode->queryProp("@FQDN");
  2063. const char* pszIpAddress = pInstanceNode->queryProp("@netAddress");
  2064. int daysValid = pHttps->getPropInt("@daysValid", -1);
  2065. if (!pszOrgUnit || !*pszOrgUnit || !pszOrg || !*pszOrg)
  2066. throw MakeStringExceptionDirect(-1, "Cannot generate SSL certificate.\nOrganizational unit or organization was not specified.");
  2067. if (!pszCity || !*pszCity || !pszState || !*pszState || !pszCountry || !*pszCountry)
  2068. throw MakeStringExceptionDirect(-1, "Cannot generate SSL certificate.\nCity, state or country was not specified.");
  2069. if (!pszPassPhrase || !*pszPassPhrase)
  2070. throw MakeStringExceptionDirect(-1, "Cannot generate SSL certificate.\nPass phrase was not specified.");
  2071. if (daysValid < -1)
  2072. throw MakeStringExceptionDirect(-1, "Cannot generate SSL certificate.\nNumber of days the certificate needs to be valid was not specified.");
  2073. //call secure socket method to generate the certificate and private key into string buffers
  2074. //
  2075. Owned<ICertificate> cc = createCertificate();
  2076. cc->setCountry(pszCountry);
  2077. cc->setState (pszState);
  2078. cc->setCity (pszCity);
  2079. cc->setOrganization(pszOrg);
  2080. cc->setOrganizationalUnit(pszOrgUnit);
  2081. cc->setDestAddr( pszFQDN && *pszFQDN ? pszFQDN : pszIpAddress); //use FQDN if available, ip address otherwise
  2082. cc->setDays (daysValid);
  2083. StringBuffer pwbuf;
  2084. decrypt(pwbuf, pszPassPhrase);
  2085. cc->setPassphrase(pwbuf.str());
  2086. cc->generate(sCertificate.clear(), sPrivKey.clear());//throws exception!
  2087. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Generating Certificate Signing Request (CSR) ...");
  2088. cc->generateCSR(sPrivKey.str(), sCSR.clear());
  2089. if (bRegenerateCSR)
  2090. pHttps->setProp("@regenerateCredentials", "false");
  2091. //set these generated values in the environment so we don't have to regenerate them later
  2092. //
  2093. if (!m_environment.isConstEnvironment())
  2094. {
  2095. pCertNode->setProp(NULL, sCertificate.str());
  2096. pPrivKeyNode->setProp(NULL, sPrivKey.str());
  2097. pCsrNode->setProp(NULL, sCSR.str());
  2098. m_pCallback->setEnvironmentUpdated();
  2099. }
  2100. }
  2101. rc = true;
  2102. break;
  2103. }
  2104. catch (IException* e)
  2105. {
  2106. StringBuffer msg;
  2107. e->errorMessage(msg);
  2108. task->setErrorString(msg.str());
  2109. task->setErrorCode((DWORD)-1);
  2110. if (m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e, NULL, NULL, task))//ignore ?
  2111. {
  2112. rc = false;
  2113. break;
  2114. }
  2115. task->setErrorCode(0);
  2116. task->setErrorString("");
  2117. }
  2118. catch (...)
  2119. {
  2120. task->setErrorString("Unknown exception!");
  2121. task->setErrorCode((DWORD)-1);
  2122. if (m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, NULL, NULL, NULL, task))//ignore ?
  2123. {
  2124. rc = false;
  2125. break;
  2126. }
  2127. task->setErrorCode(0);
  2128. task->setErrorString("");
  2129. }
  2130. }//while
  2131. m_pCallback->printStatus(task);
  2132. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  2133. //write the string buffers out to temp files
  2134. //
  2135. if (rc && (m_deployFlags & DEFLAGS_BUILDFILES))
  2136. {
  2137. //Handle certificate first ------------------------------
  2138. //
  2139. //create temp file path to save certificate
  2140. char tempfile[_MAX_PATH];
  2141. getTempPath(tempfile, sizeof(tempfile), m_name);
  2142. char* pTempFile = tempfile + strlen(tempfile);
  2143. strcpy(pTempFile, pszCertFile);
  2144. DeleteFile(tempfile);
  2145. //write certificate in this temp file
  2146. Owned<IFile> pFile = createIFile(tempfile);
  2147. IFileIO* pFileIO = pFile->open(IFOcreate);
  2148. pFileIO->write( 0, sCertificate.length(), sCertificate.str());
  2149. pFileIO->Release();
  2150. m_envDepEngine.addTempFile(tempfile);
  2151. //add this file copy operation to our todo list
  2152. Owned<CInstallFile> pInstallFile = new CInstallFile("copy", tempfile, pszCertFile);
  2153. s_dynamicFileList.push_back(StlLinkedFilePtr(pInstallFile.get()));
  2154. //Now handle private key ------------------------------
  2155. //create temp file path to save private key
  2156. strcpy(pTempFile, pszPrivFile);
  2157. DeleteFile(tempfile);
  2158. //write private key in this temp file
  2159. pFile.set( createIFile(tempfile) );
  2160. pFileIO = pFile->open(IFOcreate);
  2161. pFileIO->write( 0, sPrivKey.length(), sPrivKey.str());
  2162. pFileIO->Release();
  2163. m_envDepEngine.addTempFile(tempfile);
  2164. //add this file copy operation to our todo list
  2165. Owned<CInstallFile> pInstallFile2 = new CInstallFile("copy", tempfile, pszPrivFile);
  2166. s_dynamicFileList.push_back(StlLinkedFilePtr(pInstallFile2.get()));
  2167. }
  2168. }
  2169. bool CDeploymentEngine::fireException(IException *e)
  2170. {
  2171. StringBuffer msg;
  2172. e->errorMessage(msg);
  2173. // don't release e since that is done by our caller
  2174. //don't process abort exception since processException will throw another exception
  2175. if (strcmp(msg.str(), "Abort") != 0)
  2176. {
  2177. try
  2178. {
  2179. //BUG#48891: m_pCallback->processException() releases the exception, so bump the link count
  2180. //and let the JThread handleException release the exception
  2181. //Also note, if control comes here and we display the
  2182. //the abort, retry and ignore message box, there is no route to go back to the
  2183. //DeployTask and retry the operation. Therefore, any exception that come here
  2184. //need to be fixed to be caught and handled in the DeployTask
  2185. e->Link();
  2186. m_pCallback->processException(m_process.queryName(), m_name, m_curInstance, e);
  2187. }
  2188. catch (IException *e1)
  2189. {
  2190. // smeda: 29299
  2191. // do not rethrow exceptions from processException (as we are already in the
  2192. // middle of handling an exception). If rethrown, the jthread's parent.notifyStopped()
  2193. // is not called which in turn will keep the ThreadPool's
  2194. // joinwait() hanging forever for this thread to stop.
  2195. EXCLOG(e1,"CDeploymentEngine::fireException");
  2196. return false; // didn't handle the exception
  2197. }
  2198. }
  2199. return true; //handled the exception
  2200. }
  2201. bool CDeploymentEngine::checkSSHFileExists(const char* dir) const
  2202. {
  2203. bool flag = false;
  2204. StringBuffer destpath, destip, cmd, output, tmp, err;
  2205. stripNetAddr(dir, destpath, destip);
  2206. if (destip.length() && m_curSSHUser.length() && m_curSSHKeyFile.length())
  2207. {
  2208. tmp.appendf("%d", msTick());
  2209. cmd.clear().appendf("[ -e %s ] && echo %s", destpath.str(), tmp.str());
  2210. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Ensure Path", m_process.queryName(), m_name.get(),
  2211. m_curInstance, NULL, NULL, m_curSSHUser.sget(), m_curSSHKeyFile.sget(), m_curSSHKeyPassphrase.sget(), m_useSSHIfDefined);
  2212. task->execSSHCmd(destip.str(), cmd, output, err);
  2213. flag = strstr(output.str(), tmp.str()) == output.str();
  2214. checkAbort(task);
  2215. }
  2216. return flag;
  2217. }