deploy.cpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "deploy.hpp"
  15. #include "environment.hpp"
  16. #include "jptree.hpp"
  17. #include "jexcept.hpp"
  18. #include "jencrypt.hpp"
  19. #include "xslprocessor.hpp"
  20. #include "DeploymentEngine.hpp"
  21. #include "ThorDeploymentEngine.hpp"
  22. #include "EspDeploymentEngine.hpp"
  23. #include "dalideploymentengine.hpp"
  24. #include "RoxieDeploymentEngine.hpp"
  25. #include "configgenengine.hpp"
  26. #include "espconfiggenengine.hpp"
  27. #include "thorconfiggenengine.hpp"
  28. //---------------------------------------------------------------------------
  29. // CEnvironmentDeploymentEngine
  30. //---------------------------------------------------------------------------
  31. class CEnvironmentDeploymentEngine : public CInterface, implements IEnvDeploymentEngine
  32. {
  33. public:
  34. IMPLEMENT_IINTERFACE;
  35. //---------------------------------------------------------------------------
  36. // CEnvironmentDeploymentEngine
  37. //---------------------------------------------------------------------------
  38. CEnvironmentDeploymentEngine(IConstEnvironment &environment, IDeploymentCallback& callback,
  39. IPropertyTree* pSelectedComponents)
  40. : m_environment(environment),
  41. m_transform(NULL),
  42. m_abort(false),
  43. m_espModuleCount(0),
  44. m_tempFileCount(0),
  45. m_bLinuxDeployment(false),
  46. m_bInteractiveMode(true)
  47. {
  48. m_pCallback.set(&callback);
  49. m_validateAllXsl.clear().append("validateAll.xsl");
  50. if (pSelectedComponents)
  51. {
  52. initXML(pSelectedComponents);
  53. Owned<IPropertyTreeIterator> it = pSelectedComponents->getElements("*");
  54. ForEach(*it)
  55. {
  56. IPropertyTree* pComponent = &it->query();
  57. IDeploymentEngine* pEngine = addProcess(pComponent->queryName(), pComponent->queryProp("@name"));
  58. Owned<IPropertyTreeIterator> iter = pComponent->getElements("*");
  59. if (iter->first())
  60. {
  61. pEngine->resetInstances();
  62. ForEach(*iter)
  63. {
  64. IPropertyTree* pChild = &iter->query();
  65. const char* tagName = pChild->queryName();
  66. const char* instName = pChild->queryProp("@name");
  67. pEngine->addInstance(tagName, instName);
  68. //determine if this is linux deployment
  69. if (!m_bLinuxDeployment)
  70. {
  71. const char* computer = pChild->queryProp("@computer");
  72. IConstMachineInfo* pMachine = environment.getMachine(computer);
  73. if (pMachine->getOS() == MachineOsLinux)
  74. m_bLinuxDeployment = true;
  75. }
  76. }
  77. }
  78. else if (!m_bLinuxDeployment)//another previously added engine already does not have linux instance
  79. {
  80. //some components like thor and hole clusters don't show their instances in the
  81. //deployment wizard so detect if they have any linux instance.
  82. const IArrayOf<IPropertyTree>& instances = pEngine->getInstances();
  83. if (instances.ordinality() > 0)
  84. {
  85. Owned<IConstMachineInfo> machine = m_environment.getMachine(instances.item(0).queryProp("@computer"));
  86. if (machine && machine->getOS() == MachineOsLinux)
  87. m_bLinuxDeployment = true;
  88. }
  89. }
  90. }
  91. }
  92. #ifdef _WINDOWS
  93. EnumerateNetworkConnections();
  94. #endif
  95. }
  96. //---------------------------------------------------------------------------
  97. // ~CEnvironmentDeploymentEngine
  98. //---------------------------------------------------------------------------
  99. virtual ~CEnvironmentDeploymentEngine()
  100. {
  101. //delete all temporary files generated during deployemnt
  102. int count = m_tempFiles.length();
  103. int i;
  104. for (i = 0; i < count; i++)
  105. DeleteFile(m_tempFiles.item(i));
  106. count = m_tempDirs.length();
  107. for (i = 0; i < count; i++)
  108. deleteRecursive(m_tempDirs.item(i));
  109. m_processes.kill(); // must do this before destroying deplyCallback and deployLog
  110. m_pDeployLog.clear(); // this causes the log file to be written
  111. m_pCallback.clear();
  112. termXML();
  113. }
  114. void deleteRecursive(const char* path)
  115. {
  116. Owned<IFile> pDir = createIFile(path);
  117. if (pDir->exists())
  118. {
  119. if (pDir->isDirectory())
  120. {
  121. Owned<IDirectoryIterator> it = pDir->directoryFiles(NULL, false, true);
  122. ForEach(*it)
  123. {
  124. StringBuffer name;
  125. it->getName(name);
  126. StringBuffer childPath(path);
  127. childPath.append(PATHSEPCHAR);
  128. childPath.append(name);
  129. deleteRecursive(childPath.str());
  130. }
  131. }
  132. pDir->remove();
  133. }
  134. }
  135. //---------------------------------------------------------------------------
  136. // addProcess
  137. //---------------------------------------------------------------------------
  138. IDeploymentEngine* addProcess(const char* processType, const char* processName)
  139. {
  140. assertex(processType);
  141. assertex(processName);
  142. StringBuffer xpath;
  143. xpath.appendf("Software/%s[@name='%s']", processType, processName);
  144. Owned<IPropertyTree> tree = &m_environment.getPTree();
  145. IPropertyTree* pComponent = tree->queryPropTree(xpath.str());
  146. if (!pComponent)
  147. throw MakeStringException(0, "%s with name %s was not found!", processType, processName);
  148. IDeploymentEngine* deployEngine;
  149. if (strcmp(processType, "DaliServerProcess")==0)
  150. deployEngine = new CDaliDeploymentEngine(*this, *m_pCallback, *pComponent);
  151. else if (strcmp(processType, "ThorCluster")==0)
  152. deployEngine = new CThorDeploymentEngine(*this, *m_pCallback, *pComponent);
  153. else if (strcmp(processType, "RoxieCluster")==0)
  154. deployEngine = new CRoxieDeploymentEngine(*this, *m_pCallback, *pComponent);
  155. else if (strcmp(processType, "EspProcess")==0)
  156. deployEngine = new CEspDeploymentEngine(*this, *m_pCallback, *pComponent);
  157. else
  158. deployEngine = new CDeploymentEngine(*this, *m_pCallback, *pComponent, "Instance", true);
  159. assertex(deployEngine);
  160. deployEngine->setXsl(m_processor, m_transform);
  161. m_processes.append(*deployEngine); // array releases members when destroyed
  162. return deployEngine;
  163. }
  164. //---------------------------------------------------------------------------
  165. // setSshAccount
  166. //---------------------------------------------------------------------------
  167. void setSshAccount(const char* userid, const char* password)
  168. {
  169. m_sSshUserid = userid;
  170. m_sSshPassword = password;
  171. }
  172. //---------------------------------------------------------------------------
  173. // isLinuxDeployment
  174. //---------------------------------------------------------------------------
  175. bool isLinuxDeployment() const
  176. {
  177. return m_bLinuxDeployment;
  178. }
  179. //---------------------------------------------------------------------------
  180. // start
  181. //---------------------------------------------------------------------------
  182. void start()
  183. {
  184. ForEachItemIn(idx, m_processes)
  185. {
  186. m_processes.item(idx).start();
  187. }
  188. }
  189. //---------------------------------------------------------------------------
  190. // stop
  191. //---------------------------------------------------------------------------
  192. void stop()
  193. {
  194. ForEachItemInRev(idx, m_processes)
  195. {
  196. m_processes.item(idx).stop();
  197. }
  198. }
  199. //---------------------------------------------------------------------------
  200. // stripXsltMessage
  201. //---------------------------------------------------------------------------
  202. void stripXsltMessage(StringBuffer& msg)
  203. {
  204. //for better readability of msg, remove redundant prefix of "[XSLT warning: ", if present
  205. const char* pattern = "[ElemMessageTerminateException: ";
  206. const int len =sizeof("[ElemMessageTerminateException: ")-1;
  207. if (!strncmp(msg, pattern, len))
  208. msg.remove(0, len);
  209. //remove the excessive info about XSLT context when this was thrown
  210. const char* begin = msg.str();
  211. const char* end = strstr(begin, "(file:");
  212. if (end)
  213. msg.setLength(end-begin);
  214. }
  215. //---------------------------------------------------------------------------
  216. // check
  217. //---------------------------------------------------------------------------
  218. void check()
  219. {
  220. if (m_pCallback->getAbortStatus())
  221. throw MakeStringException(0, "User abort");
  222. bool valid = false;
  223. m_nValidationErrors = 0;
  224. StringBuffer outputXml;
  225. Owned<IXslFunction> externalFunction;
  226. externalFunction.setown(m_transform->createExternalFunction("validationMessage", validationMessageFromXSLT));
  227. m_transform->setExternalFunction(SEISINT_NAMESPACE, externalFunction.get(), true);
  228. m_transform->loadXslFromFile(m_validateAllXsl.str());
  229. m_transform->setUserData(this);
  230. try
  231. {
  232. m_transform->transform( outputXml );
  233. m_transform->closeResultTarget();
  234. const char* msg = m_transform->getMessages();
  235. if (msg && *msg)
  236. {
  237. /*
  238. //there may be multiple warnings messages bundled here so process each of them:
  239. StringArray msgs;
  240. DelimToStringArray(msg, msgs, "\n");
  241. ForEachItemIn(idx, msgs)
  242. {
  243. msg = msgs.item(idx);
  244. if (msg && *msg)
  245. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, msg);
  246. }
  247. */
  248. m_sValidationErrors.append(msg);
  249. m_nValidationErrors++;
  250. }
  251. if (!m_nValidationErrors)//this may get filled in by the external function
  252. valid = true;
  253. }
  254. catch (IException* e)
  255. {
  256. StringBuffer msg;
  257. e->errorMessage(msg);
  258. e->Release();
  259. stripXsltMessage(msg);
  260. m_sValidationErrors.append(msg);
  261. }
  262. catch (...)
  263. {
  264. m_sValidationErrors.appendf("Validation failed: Unspecified XSL error!");
  265. }
  266. m_transform->setExternalFunction(SEISINT_NAMESPACE, externalFunction.get(), false);
  267. m_transform->setUserData(NULL);
  268. if (!valid)
  269. {
  270. const char* errors = m_sValidationErrors.str();
  271. if (!errors || !*errors)
  272. errors = "Continue?";
  273. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Preliminary validation failed!");
  274. while ( !m_pCallback->processException(NULL, NULL, NULL, NULL, errors, "Preliminary validation failed!", NULL) )
  275. ;
  276. valid = true; //ignore validation errors
  277. }
  278. if (valid)
  279. {
  280. ForEachItemIn(idx, m_processes)
  281. m_processes.item(idx).check();
  282. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  283. }
  284. }
  285. //---------------------------------------------------------------------------
  286. // compare
  287. //---------------------------------------------------------------------------
  288. void compare(unsigned mode)
  289. {
  290. ForEachItemIn(idx, m_processes)
  291. {
  292. m_processes.item(idx).compare(mode);
  293. }
  294. }
  295. //---------------------------------------------------------------------------
  296. // deploy
  297. //---------------------------------------------------------------------------
  298. void deploy(unsigned flags, bool useTempDir)
  299. {
  300. m_tempFileCount = m_espModuleCount = 0;
  301. if (flags != DEFLAGS_NONE)
  302. {
  303. ForEachItemIn(idx, m_processes)
  304. {
  305. m_processes.item(idx).deploy(flags, useTempDir);
  306. }
  307. }
  308. }
  309. //---------------------------------------------------------------------------
  310. // deploy
  311. //---------------------------------------------------------------------------
  312. void deploy(unsigned flags, BackupMode backupMode, bool bStop, bool bStart)
  313. {
  314. switch (backupMode)
  315. {
  316. case DEBACKUP_NONE:
  317. if (bStop)
  318. stop();
  319. deploy(flags, false);
  320. if (bStart)
  321. start();
  322. break;
  323. case DEBACKUP_COPY:
  324. backupDirs();
  325. if (bStop)
  326. stop();
  327. deploy(flags, false);
  328. if (bStart)
  329. start();
  330. break;
  331. case DEBACKUP_RENAME:
  332. deploy(flags, true);
  333. if (bStop)
  334. stop();
  335. renameDirs();
  336. if (bStart)
  337. start();
  338. break;
  339. default:
  340. assertex(false);
  341. }
  342. }
  343. //---------------------------------------------------------------------------
  344. // renameDirs
  345. //---------------------------------------------------------------------------
  346. void renameDirs()
  347. {
  348. ForEachItemIn(idx, m_processes)
  349. {
  350. m_processes.item(idx).renameDirs();
  351. }
  352. }
  353. //---------------------------------------------------------------------------
  354. // backupDirs
  355. //---------------------------------------------------------------------------
  356. void backupDirs()
  357. {
  358. ForEachItemIn(idx, m_processes)
  359. {
  360. m_processes.item(idx).backupDirs();
  361. }
  362. }
  363. //---------------------------------------------------------------------------
  364. // abort
  365. //---------------------------------------------------------------------------
  366. void abort()
  367. {
  368. m_abort = true;
  369. ForEachItemIn(idx, m_processes)
  370. {
  371. m_processes.item(idx).abort();
  372. }
  373. }
  374. //---------------------------------------------------------------------------
  375. // archive
  376. //---------------------------------------------------------------------------
  377. void archive(const char* filename)
  378. {
  379. if (!filename || !*filename) return;
  380. if (m_abort)
  381. {
  382. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Aborted!");
  383. throw MakeStringException(0, "User abort");
  384. }
  385. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Archiving environment data to %s...", filename);
  386. Owned<IPropertyTree> tree = &m_environment.getPTree();
  387. StringBuffer xml;
  388. toXML(tree, xml);
  389. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Archive File", NULL, NULL, NULL, NULL,
  390. filename, "", "", "", false);
  391. task->createFile(xml.str());
  392. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL);
  393. if (task->getAbort())
  394. throw MakeStringException(0, "User abort");
  395. Owned<IFile> pFile = createIFile(filename);
  396. pFile->setReadOnly(true);
  397. }
  398. //---------------------------------------------------------------------------
  399. // setLog
  400. //---------------------------------------------------------------------------
  401. void setLog(const char* filename, const char* envname)
  402. {
  403. if (!filename || !*filename) return;
  404. m_pDeployLog.setown(createDeployLog(*m_pCallback, filename, envname));
  405. }
  406. //---------------------------------------------------------------------------
  407. // initXML
  408. //---------------------------------------------------------------------------
  409. void initXML(IPropertyTree* pSelectedComponents)
  410. {
  411. if (m_abort)
  412. throw MakeStringException(0, "User abort");
  413. m_pCallback->printStatus(STATUS_NORMAL, NULL, NULL, NULL, "Loading environment...");
  414. m_processor.setown(getXslProcessor());
  415. m_transform.setown(m_processor->createXslTransform());
  416. //decrypt external function is no longer used by any xslt
  417. //
  418. //m_externalFunction.setown(m_transform->createExternalFunction("decrypt", decrypt));
  419. //m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction.get(), true);
  420. Owned<IPropertyTree> tree = &m_environment.getPTree();
  421. IPropertyTree* pDeploy = tree->queryPropTree("DeployComponents");
  422. if (pDeploy)
  423. tree->removeTree(pDeploy);
  424. pDeploy = tree->addPropTree("DeployComponents", createPTreeFromIPT(pSelectedComponents));
  425. StringBuffer xml;
  426. toXML(tree, xml);
  427. tree->removeTree(pDeploy);
  428. if (m_transform->setXmlSource(xml.str(), xml.length()) != 0)
  429. throw MakeStringException(0, "Invalid environment XML string");
  430. }
  431. //---------------------------------------------------------------------------
  432. // termXML
  433. //---------------------------------------------------------------------------
  434. void termXML()
  435. {
  436. //decrypt external function is no longer used by any xslt
  437. //
  438. //m_transform->setExternalFunction(SEISINT_NAMESPACE, m_externalFunction.get(), false);
  439. m_externalFunction.clear();
  440. m_transform.clear();
  441. m_processor.clear();
  442. }
  443. //---------------------------------------------------------------------------
  444. // incrementTempFileCount
  445. //---------------------------------------------------------------------------
  446. virtual int incrementTempFileCount()
  447. {
  448. return ++m_tempFileCount;
  449. }
  450. //---------------------------------------------------------------------------
  451. // incrementEspModuleCount
  452. //---------------------------------------------------------------------------
  453. virtual int incrementEspModuleCount()
  454. {
  455. return ++m_espModuleCount;
  456. }
  457. //---------------------------------------------------------------------------
  458. // validationMessageFromXSLT
  459. //---------------------------------------------------------------------------
  460. static void validationMessageFromXSLT(StringBuffer &ret, const char *in, IXslTransform* pTransform)
  461. {
  462. CEnvironmentDeploymentEngine* pEnvDepEngine = (CEnvironmentDeploymentEngine*) pTransform->getUserData();
  463. IDeploymentCallback* pCallback = pEnvDepEngine->m_pCallback;
  464. //input 'in' has format of the form [type]:[compType]:[compName]:[message]
  465. //type is either 'error' or 'warning' and any of the other parts may be empty strings
  466. //
  467. StringArray sArray;
  468. DelimToStringArray(in, sArray, ":");
  469. if (sArray.ordinality() != 4)
  470. {
  471. pCallback->printStatus(STATUS_ERROR, NULL, NULL, NULL, "%s", in);
  472. return;
  473. }
  474. const char* msgType = sArray.item(0);
  475. const char* compType = sArray.item(1);
  476. const char* compName = sArray.item(2);
  477. const char* msg = sArray.item(3);
  478. if (compType && !*compType)
  479. compType = NULL;
  480. if (compName && !*compName)
  481. compName = NULL;
  482. StatusType statusType;
  483. if (!stricmp(msgType, "error"))
  484. {
  485. statusType = STATUS_ERROR;
  486. pEnvDepEngine->m_nValidationErrors++;
  487. if (!compType || !compName)//if this error is not being reported under a particular component in tree
  488. pEnvDepEngine->m_sValidationErrors.append(msg).append("\n");
  489. }
  490. else if (!strnicmp(msgType, "warn", 4))
  491. statusType = STATUS_WARN;
  492. else if (!stricmp(msgType, "OK"))
  493. statusType = STATUS_OK;
  494. else if (!strnicmp(msgType, "inc", 3))
  495. statusType = STATUS_INCOMPLETE;
  496. else statusType = !stricmp(msgType, "normal") ? STATUS_NORMAL : STATUS_ERROR;
  497. try
  498. {
  499. if (pCallback)
  500. pCallback->printStatus( statusType,
  501. compType,
  502. compName,
  503. NULL,
  504. "%s", msg);
  505. }
  506. catch (IException* e)
  507. {
  508. StringBuffer buf;
  509. e->errorMessage(buf);
  510. e->Release();
  511. pCallback->printStatus(STATUS_ERROR, NULL, NULL, NULL, "%s", buf.str());
  512. }
  513. catch(...)
  514. {
  515. pCallback->printStatus(STATUS_ERROR, NULL, NULL, NULL, "Unknown exception!");
  516. }
  517. }
  518. //---------------------------------------------------------------------------
  519. // getCallback
  520. //---------------------------------------------------------------------------
  521. virtual IDeploymentCallback& getCallback() const
  522. {
  523. return *m_pCallback;
  524. }
  525. //---------------------------------------------------------------------------
  526. // setInteractiveMode
  527. //---------------------------------------------------------------------------
  528. virtual void setInteractiveMode(bool bSet)
  529. {
  530. m_bInteractiveMode = bSet;
  531. }
  532. //---------------------------------------------------------------------------
  533. // getEnvironment
  534. //---------------------------------------------------------------------------
  535. IConstEnvironment& getEnvironment() const
  536. {
  537. return m_environment;
  538. }
  539. //---------------------------------------------------------------------------
  540. // getInteractiveMode
  541. //---------------------------------------------------------------------------
  542. virtual bool getInteractiveMode() const
  543. {
  544. return m_bInteractiveMode;
  545. }
  546. //---------------------------------------------------------------------------
  547. // getDeployLog
  548. //---------------------------------------------------------------------------
  549. virtual IDeployLog* getDeployLog()
  550. {
  551. return m_pDeployLog ? m_pDeployLog.getLink() : NULL;
  552. }
  553. //---------------------------------------------------------------------------
  554. // addTempFile
  555. //---------------------------------------------------------------------------
  556. virtual void addTempFile(const char* filePath)
  557. {
  558. if (filePath)
  559. m_tempFiles.append(filePath);
  560. }
  561. //---------------------------------------------------------------------------
  562. // addTempDirectory
  563. //---------------------------------------------------------------------------
  564. virtual void addTempDirectory(const char* dirPath)
  565. {
  566. if (dirPath)
  567. m_tempDirs.append(dirPath);
  568. }
  569. //---------------------------------------------------------------------------
  570. // setDeployToFolder
  571. //---------------------------------------------------------------------------
  572. virtual void setDeployToFolder(const char* path)
  573. {
  574. StringBuffer machineName;
  575. StringBuffer localPath;
  576. StringBuffer tail;
  577. StringBuffer ext;
  578. if (splitUNCFilename(path, &machineName, &localPath, &tail, &ext))
  579. {
  580. const char* hostName = machineName.str() + 2;
  581. Owned<IConstMachineInfo> machine = m_environment.getMachine(hostName);
  582. if (!machine)
  583. throw MakeStringException(-1, "The computer '%s' used for deployment folder is undefined!", hostName);
  584. StringAttr netAddress;
  585. StringAttrAdaptor adaptor(netAddress);
  586. machine->getNetAddress(adaptor);
  587. if (!netAddress.get() || !*netAddress.get())
  588. throw MakeStringException(-1,
  589. "The computer '%s' used for deployment folder does not have any network address defined!", hostName);
  590. StringBuffer uncPath(PATHSEPSTR PATHSEPSTR);
  591. uncPath.append( netAddress.get() );
  592. if (*localPath.str() != PATHSEPCHAR)
  593. uncPath.append( PATHSEPCHAR );
  594. uncPath.append( localPath );//note that the path ends with PATHSEPCHAR
  595. uncPath.append( tail );
  596. uncPath.append( ext );
  597. m_sDeployToFolder.set( uncPath.str() );
  598. getAccountInfo(hostName, m_sDeployToUser, m_sDeployToPswd);
  599. }
  600. else
  601. m_sDeployToFolder.set( path );
  602. /*
  603. Owned<IDeployTask> task = createDeployTask(*m_pCallback, "Create Directory", NULL, NULL, NULL, NULL, m_sDeployToFolder.get());
  604. m_pCallback->printStatus(task);
  605. task->createDirectory();
  606. m_pCallback->printStatus(task);
  607. */
  608. }
  609. //---------------------------------------------------------------------------
  610. // getDeployToFolder
  611. //---------------------------------------------------------------------------
  612. virtual const char* getDeployToFolder() const
  613. {
  614. return m_sDeployToFolder.get();
  615. }
  616. //---------------------------------------------------------------------------
  617. // getDeployToAccountInfo
  618. //---------------------------------------------------------------------------
  619. virtual void getDeployToAccountInfo(const char*& user, const char*& pswd) const
  620. {
  621. user = m_sDeployToUser.get();
  622. pswd = m_sDeployToPswd.get();
  623. }
  624. //---------------------------------------------------------------------------
  625. // lookupNetAddress
  626. //---------------------------------------------------------------------------
  627. StringAttr& lookupNetAddress(StringAttr& str, const char* computer) const
  628. {
  629. Owned<IConstMachineInfo> machine = m_environment.getMachine(computer);
  630. if (machine)
  631. {
  632. StringAttrAdaptor adaptor(str);
  633. machine->getNetAddress(adaptor);
  634. }
  635. return str;
  636. }
  637. //---------------------------------------------------------------------------
  638. // lookupMachineOS
  639. //---------------------------------------------------------------------------
  640. EnvMachineOS lookupMachineOS(IPropertyTree& node) const
  641. {
  642. Owned<IConstMachineInfo> machine = m_environment.getMachine(node.queryProp("@computer"));
  643. return machine ? machine->getOS() : MachineOsUnknown;
  644. }
  645. //---------------------------------------------------------------------------
  646. // getAccountInfo
  647. //---------------------------------------------------------------------------
  648. void getAccountInfo(const char* computer, StringAttr& user, StringAttr& pwd) const
  649. {
  650. Owned<IConstMachineInfo> machine = m_environment.getMachine(computer);
  651. if (machine)
  652. {
  653. Owned<IConstDomainInfo> domain = machine->getDomain();
  654. if (!domain)
  655. throw MakeStringException(-1, "The computer '%s' does not have any domain information!", computer);
  656. StringBuffer x;
  657. if (machine->getOS() == MachineOsW2K)
  658. {
  659. domain->getName(StringBufferAdaptor(x));
  660. if (x.length())
  661. x.append(PATHSEPCHAR);
  662. }
  663. domain->getAccountInfo(StringBufferAdaptor(x), StringAttrAdaptor(pwd));
  664. user.set(x.str());
  665. }
  666. else
  667. throw MakeStringException(-1, "The computer '%s' is undefined!", computer);
  668. }
  669. //---------------------------------------------------------------------------
  670. // getSSHAccountInfo
  671. //---------------------------------------------------------------------------
  672. void getSSHAccountInfo(const char* computer, StringAttr& user, StringAttr& sshKeyFile, StringAttr& sshKeyPassphrase) const
  673. {
  674. Owned<IConstMachineInfo> machine = m_environment.getMachine(computer);
  675. if (machine)
  676. {
  677. Owned<IConstDomainInfo> domain = machine->getDomain();
  678. if (!domain)
  679. throw MakeStringException(-1, "The computer '%s' does not have any domain information!", computer);
  680. StringBuffer x;
  681. if (machine->getOS() == MachineOsW2K)
  682. {
  683. domain->getName(StringBufferAdaptor(x));
  684. if (x.length())
  685. x.append(PATHSEPCHAR);
  686. }
  687. domain->getSSHAccountInfo(StringBufferAdaptor(x), StringAttrAdaptor(sshKeyFile), StringAttrAdaptor(sshKeyPassphrase));
  688. user.set(x.str());
  689. }
  690. else
  691. throw MakeStringException(-1, "The computer '%s' is undefined!", computer);
  692. }
  693. virtual void setSourceDaliAddress( const char* addr )
  694. {
  695. m_sSrcDaliAddress.set( addr );
  696. }
  697. virtual const char* getSourceDaliAddress()
  698. {
  699. return m_sSrcDaliAddress.get();
  700. }
  701. virtual IArrayOf<IDeploymentEngine>& queryProcesses() { return m_processes; }
  702. #ifdef _WINDOWS
  703. void NetErrorHandler(DWORD dwResult)
  704. {
  705. StringBuffer out;
  706. formatSystemError(out, dwResult);
  707. out.insert(0, "Failed to enumerate existing network connections:\n");
  708. while ( !m_pCallback->processException(NULL, NULL, NULL, NULL, out, "Network Error", NULL) )
  709. ;
  710. }
  711. bool EnumerateNetworkConnections()
  712. {
  713. DWORD dwResult;
  714. HANDLE hEnum;
  715. DWORD cbBuffer = 16384; // 16K is a good size
  716. DWORD cEntries = -1; // enumerate all possible entries
  717. LPNETRESOURCE lpnr; // pointer to enumerated structures
  718. //
  719. // Call the WNetOpenEnum function to begin the enumeration.
  720. //
  721. dwResult = WNetOpenEnum(RESOURCE_CONNECTED, // connected network resources
  722. RESOURCETYPE_ANY,// all resources
  723. 0, // enumerate all resources
  724. NULL, // NULL first time the function is called
  725. &hEnum); // handle to the resource
  726. if (dwResult != NO_ERROR)
  727. {
  728. NetErrorHandler(dwResult);
  729. return false;
  730. }
  731. //
  732. // Call the GlobalAlloc function to allocate resources.
  733. //
  734. lpnr = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
  735. do
  736. {
  737. ZeroMemory(lpnr, cbBuffer);
  738. // Call the WNetEnumResource function to continue
  739. // the enumeration.
  740. //
  741. dwResult = WNetEnumResource( hEnum, // resource handle
  742. &cEntries, // defined locally as -1
  743. lpnr, // LPNETRESOURCE
  744. &cbBuffer); // buffer size
  745. // If the call succeeds, loop through the structures.
  746. //
  747. if (dwResult == NO_ERROR)
  748. {
  749. StringBuffer networkPath;
  750. for (DWORD i = 0; i < cEntries; i++)
  751. if (lpnr[i].lpRemoteName)
  752. {
  753. // make a valid UNC path to connect to and see if we are not already connected
  754. if (CDeploymentEngine::stripTrailingDirsFromUNCPath(lpnr[i].lpRemoteName, networkPath.clear()) &&
  755. m_persistentConnections.find( networkPath.str() ) == m_persistentConnections.end())
  756. {
  757. //::MessageBox(NULL, networkPath.str(), lpnr[i].lpRemoteName, MB_OK);
  758. m_persistentConnections.insert( networkPath.str() );
  759. }
  760. }
  761. }
  762. else if (dwResult != ERROR_NO_MORE_ITEMS)
  763. {
  764. NetErrorHandler(dwResult);
  765. break;
  766. }
  767. }
  768. while (dwResult != ERROR_NO_MORE_ITEMS);
  769. GlobalFree((HGLOBAL)lpnr); // free the memory
  770. dwResult = WNetCloseEnum(hEnum); // end the enumeration
  771. if (dwResult != NO_ERROR)
  772. {
  773. NetErrorHandler(dwResult);
  774. return false;
  775. }
  776. return true;
  777. }
  778. #endif//WINDOWS
  779. virtual bool IsPersistentConnection(const char* networkPath) const
  780. {
  781. return m_persistentConnections.find( networkPath ) != m_persistentConnections.end();
  782. }
  783. protected:
  784. IArrayOf<IDeploymentEngine> m_processes;
  785. IConstEnvironment& m_environment;
  786. Owned<IDeploymentCallback> m_pCallback;
  787. Owned<IXslProcessor> m_processor;
  788. Owned<IXslTransform> m_transform;
  789. Owned<IXslFunction> m_externalFunction;
  790. Owned<IDeployLog> m_pDeployLog;
  791. set<string> m_persistentConnections;
  792. int m_espModuleCount;
  793. int m_tempFileCount;
  794. bool m_abort;
  795. bool m_bLinuxDeployment;
  796. bool m_bInteractiveMode;
  797. StringBuffer m_sSshUserid;
  798. StringBuffer m_sSshPassword;
  799. StringBuffer m_validateAllXsl;
  800. unsigned int m_nValidationErrors;
  801. StringBuffer m_sValidationErrors;
  802. StringArray m_tempFiles;
  803. StringArray m_tempDirs;
  804. StringAttr m_sDeployToFolder;
  805. StringAttr m_sDeployToUser;
  806. StringAttr m_sDeployToPswd;
  807. StringAttr m_sSrcDaliAddress;
  808. };
  809. class CConfigGenMgr : public CEnvironmentDeploymentEngine
  810. {
  811. public:
  812. IMPLEMENT_IINTERFACE;
  813. //---------------------------------------------------------------------------
  814. // CConfigGenMgr
  815. //---------------------------------------------------------------------------
  816. CConfigGenMgr(IConstEnvironment& environment, IDeploymentCallback& callback,
  817. IPropertyTree* pSelectedComponents, const char* inputDir, const char* outputDir, const char* compName, const char* compType, const char* ipAddr)
  818. : CEnvironmentDeploymentEngine(environment, callback, pSelectedComponents),
  819. m_inDir(inputDir),
  820. m_outDir(outputDir),
  821. m_compName(compName),
  822. m_compType(compType),
  823. m_hostIpAddr(ipAddr)
  824. {
  825. m_validateAllXsl.clear().append(inputDir);
  826. if (m_validateAllXsl.length() > 0 &&
  827. m_validateAllXsl.charAt(m_validateAllXsl.length() - 1) != PATHSEPCHAR)
  828. m_validateAllXsl.append(PATHSEPCHAR);
  829. m_validateAllXsl.append("validateAll.xsl");
  830. Owned<IPropertyTree> pSelComps;
  831. if (!pSelectedComponents)
  832. {
  833. Owned<IPropertyTree> pEnvTree = &m_environment.getPTree();
  834. pSelComps.setown(getInstances(pEnvTree, compName, compType, ipAddr));
  835. pSelectedComponents = pSelComps;
  836. }
  837. initXML(pSelectedComponents);
  838. {
  839. Owned<IPropertyTreeIterator> it = pSelectedComponents->getElements("*");
  840. ForEach(*it)
  841. {
  842. IPropertyTree* pComponent = &it->query();
  843. IDeploymentEngine* pEngine = addProcess(pComponent->queryName(), pComponent->queryProp("@name"));
  844. Owned<IPropertyTreeIterator> iter = pComponent->getElements("*");
  845. if (iter->first())
  846. {
  847. pEngine->resetInstances();
  848. ForEach(*iter)
  849. {
  850. IPropertyTree* pChild = &iter->query();
  851. const char* tagName = pChild->queryName();
  852. const char* instName = pChild->queryProp("@name");
  853. pEngine->addInstance(tagName, instName);
  854. //determine if this is linux deployment
  855. if (!m_bLinuxDeployment)
  856. {
  857. const char* computer = pChild->queryProp("@computer");
  858. Owned<IConstMachineInfo> pMachine = environment.getMachine(computer);
  859. if (!pMachine)
  860. throw MakeStringException(0, "Invalid Environment file. Instance '%s' of '%s' references a computer '%s' that has not been defined!", pChild->queryProp("@name"), pComponent->queryProp("@name"), computer);
  861. else if (pMachine->getOS() == MachineOsLinux)
  862. m_bLinuxDeployment = true;
  863. }
  864. }
  865. }
  866. else if (!m_bLinuxDeployment)//another previously added engine already does not have linux instance
  867. {
  868. //some components like thor and hole clusters don't show their instances in the
  869. //deployment wizard so detect if they have any linux instance.
  870. const IArrayOf<IPropertyTree>& instances = pEngine->getInstances();
  871. if (instances.ordinality() > 0)
  872. {
  873. Owned<IConstMachineInfo> machine;// = m_environment.getMachine(instances.item(0).queryProp("@computer"));
  874. if (machine && machine->getOS() == MachineOsLinux)
  875. m_bLinuxDeployment = true;
  876. }
  877. }
  878. }
  879. }
  880. }
  881. //---------------------------------------------------------------------------
  882. // addProcess
  883. //---------------------------------------------------------------------------
  884. IDeploymentEngine* addProcess(const char* processType, const char* processName)
  885. {
  886. assertex(processType);
  887. assertex(processName);
  888. StringBuffer xpath;
  889. xpath.appendf("Software/%s[@name='%s']", processType, processName);
  890. Owned<IPropertyTree> tree = &m_environment.getPTree();
  891. IPropertyTree* pComponent = tree->queryPropTree(xpath.str());
  892. if (!pComponent)
  893. throw MakeStringException(0, "%s with name %s was not found!", processType, processName);
  894. IDeploymentEngine* deployEngine;
  895. if (strcmp(processType, "RoxieCluster")==0)
  896. deployEngine = new CConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir, "*");
  897. else if (strcmp(processType, "ThorCluster")==0)
  898. deployEngine = new CThorConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir);
  899. else if (strcmp(processType, "EspProcess")==0)
  900. deployEngine = new CEspConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir);
  901. else
  902. deployEngine = new CConfigGenEngine(*this, *m_pCallback, *pComponent, m_inDir, m_outDir, "Instance", true);
  903. assertex(deployEngine);
  904. deployEngine->setXsl(m_processor, m_transform);
  905. m_processes.append(*deployEngine); // array releases members when destroyed
  906. return deployEngine;
  907. }
  908. void deploy(unsigned flags, BackupMode backupMode, bool bStop, bool bStart)
  909. {
  910. switch (backupMode)
  911. {
  912. case DEBACKUP_NONE:
  913. check();
  914. CEnvironmentDeploymentEngine::deploy(flags, false);
  915. break;
  916. case DEBACKUP_COPY:
  917. throw MakeStringException(-1, "Invalid option Backup copy while generating configurations");
  918. case DEBACKUP_RENAME:
  919. throw MakeStringException(-1, "Invalid option Backup rename while generating configurations");
  920. default:
  921. throw MakeStringException(-1, "Invalid option while generating configurations");
  922. }
  923. }
  924. private:
  925. StringBuffer m_inDir;
  926. StringBuffer m_outDir;
  927. StringBuffer m_compName;
  928. StringBuffer m_compType;
  929. StringBuffer m_hostIpAddr;
  930. };
  931. //---------------------------------------------------------------------------
  932. // Factory functions
  933. //---------------------------------------------------------------------------
  934. IEnvDeploymentEngine* createEnvDeploymentEngine(IConstEnvironment& environment,
  935. IDeploymentCallback& callback,
  936. IPropertyTree* pSelectedComponents)
  937. {
  938. try
  939. {
  940. return new CEnvironmentDeploymentEngine(environment, callback, pSelectedComponents);
  941. }
  942. catch (IException* e)
  943. {
  944. throw e;
  945. }
  946. catch(...)
  947. {
  948. throw MakeStringException(-1, "Unknown exception!");
  949. }
  950. }
  951. IEnvDeploymentEngine* createConfigGenMgr(IConstEnvironment& env,
  952. IDeploymentCallback& callback,
  953. IPropertyTree* pSelectedComponents,
  954. const char* inputDir,
  955. const char* outputDir,
  956. const char* compName,
  957. const char* compType,
  958. const char* ipAddr)
  959. {
  960. try
  961. {
  962. StringBuffer inDir(inputDir);
  963. if (inDir.length() && inDir.charAt(inDir.length() - 1) != PATHSEPCHAR)
  964. inDir.append(PATHSEPCHAR);
  965. StringBuffer outDir(outputDir);
  966. if (outDir.length() && outDir.charAt(outDir.length() - 1) != PATHSEPCHAR)
  967. outDir.append(PATHSEPCHAR);
  968. return new CConfigGenMgr(env, callback, pSelectedComponents, inDir.str(), outDir.str(), compName, compType, ipAddr);
  969. }
  970. catch (IException* e)
  971. {
  972. throw e;
  973. }
  974. catch(...)
  975. {
  976. throw MakeStringException(-1, "Unknown exception!");
  977. }
  978. }
  979. bool matchDeployAddress(const char *searchIP, const char *envIP)
  980. {
  981. if (searchIP && envIP && *searchIP && *envIP)
  982. {
  983. IpAddress ip(envIP);
  984. if (strcmp(searchIP, ".")==0)
  985. return ip.isLocal();
  986. else
  987. {
  988. IpAddress ip2(searchIP);
  989. return ip.ipequals(ip2);
  990. }
  991. }
  992. return false;
  993. }
  994. IPropertyTree* getInstances(const IPropertyTree* pEnvRoot, const char* compName,
  995. const char* compType, const char* ipAddr, bool listall)
  996. {
  997. Owned<IPropertyTree> pSelComps(createPTree("SelectedComponents"));
  998. Owned<IPropertyTreeIterator> iter = pEnvRoot->getElements("Software/*");
  999. const char* instanceNodeNames[] = { "Instance", "RoxieServerProcess", "RoxieSlaveProcess" };
  1000. const char* logDirNames[] = { "@logDir", "@LogDir", "@dfuLogDir", "@eclLogDir" };
  1001. ForEach(*iter)
  1002. {
  1003. IPropertyTree* pComponent = &iter->query();
  1004. const char* type = pComponent->queryName();
  1005. if (stricmp(type, "Topology")!=0 && stricmp(type, "Directories")!=0 &&
  1006. ((!compName && !compType) || (compName && !strcmp(pComponent->queryProp("@name"), compName)) ||
  1007. (!compName && compType && !strcmp(pComponent->queryProp("@buildSet"), compType))))
  1008. {
  1009. const char* name = pComponent->queryProp("@name");
  1010. const char* build = pComponent->queryProp("@build");
  1011. const char* buildSet= pComponent->queryProp("@buildSet");
  1012. const char* logDir = NULL;
  1013. if (listall)
  1014. for (int i = 0; i < sizeof(logDirNames)/sizeof(char*); i++)
  1015. {
  1016. logDir = pComponent->queryProp(logDirNames[i]);
  1017. if (logDir)
  1018. break;
  1019. }
  1020. StringBuffer sXPath;
  1021. sXPath.appendf("Programs/Build[@name='%s']/BuildSet[@name='%s']/@deployable", build, buildSet);
  1022. const char* deployable = pEnvRoot->queryProp(sXPath.str());
  1023. //either the @deployable does not exist or it is not one of 'no', 'false' or '0'
  1024. if (!deployable ||
  1025. (strcmp(deployable, "no") != 0 && strcmp(deployable, "false") != 0 && strcmp(deployable, "0") != 0))
  1026. {
  1027. IPropertyTree* pSelComp = NULL;
  1028. Owned<IPropertyTreeIterator> iterInst = pComponent->getElements("*", iptiter_sort);
  1029. bool bAdded = false;
  1030. ForEach(*iterInst)
  1031. {
  1032. IPropertyTree* pInst = &iterInst->query();
  1033. const char* computer = pInst->queryProp("@computer");
  1034. const char* netAddr = pInst->queryProp("@netAddress");
  1035. if (!computer || !*computer || !strcmp("Notes", pInst->queryName()))
  1036. continue;
  1037. if (!strcmp(buildSet, "thor"))
  1038. {
  1039. sXPath.clear().appendf("Hardware/Computer[@name=\"%s\"]", computer);
  1040. IPropertyTree* pComputer = pEnvRoot->queryPropTree(sXPath.str());
  1041. netAddr = pComputer->queryProp("@netAddress");
  1042. if (matchDeployAddress(ipAddr, netAddr) ||
  1043. (!ipAddr && netAddr && *netAddr))
  1044. {
  1045. if (!bAdded)
  1046. {
  1047. pSelComp = pSelComps->addPropTree(pComponent->queryName(), createPTree());
  1048. pSelComp->addProp("@name", name);
  1049. pSelComp->addProp("@buildSet", buildSet);
  1050. pSelComp->addProp("@logDir", logDir);
  1051. bAdded = true;
  1052. }
  1053. if (listall)
  1054. {
  1055. IPropertyTree* pInstance = pSelComp->addPropTree(pInst->queryName(), createPTree());
  1056. pInstance->addProp("@name", pInst->queryProp("@name"));
  1057. pInstance->addProp("@computer", computer);
  1058. pInstance->addProp("@netAddress", netAddr);
  1059. }
  1060. }
  1061. }
  1062. else if (matchDeployAddress(ipAddr, netAddr) ||
  1063. (!ipAddr && netAddr && *netAddr))
  1064. {
  1065. if (!bAdded)
  1066. {
  1067. pSelComp = pSelComps->addPropTree(pComponent->queryName(), createPTree());
  1068. pSelComp->addProp("@name", name);
  1069. pSelComp->addProp("@buildSet", buildSet);
  1070. pSelComp->addProp("@logDir", logDir);
  1071. bAdded = true;
  1072. }
  1073. StringBuffer sb(pInst->queryName());
  1074. for (UINT i=0; i<sizeof(instanceNodeNames) / sizeof(instanceNodeNames[0]); i++)
  1075. if (!strcmp(sb.str(), instanceNodeNames[i]))
  1076. {
  1077. //allow multiple instances but do not allow either roxie servers or slaves more than once per computer
  1078. if (listall || sb.str()[0] != 'R' || !pSelComp->queryPropTree(StringBuffer().appendf("*[@computer=\"%s\"]", computer)))
  1079. {
  1080. IPropertyTree* pInstance = pSelComp->addPropTree(sb.str(), createPTree());
  1081. pInstance->addProp("@name", pInst->queryProp("@name"));
  1082. pInstance->addProp("@computer", pInst->queryProp("@computer"));
  1083. pInstance->addProp("@port", pInst->queryProp("@port"));
  1084. pInstance->addProp("@netAddress", pInst->queryProp("@netAddress"));
  1085. const char* directory = pInst->queryProp(sb.str()[0]=='R' ? "@dataDirectory" : "@directory");
  1086. if (directory && *directory)
  1087. pInstance->addProp("@directory", directory);
  1088. }
  1089. break;
  1090. }
  1091. }
  1092. }
  1093. }
  1094. }
  1095. }
  1096. return pSelComps.getLink();
  1097. }
  1098. //---------------------------------------------------------------------------
  1099. // Module Globals
  1100. //---------------------------------------------------------------------------
  1101. const char* findFileExtension(const char* pszPath)
  1102. {
  1103. const char* lastSlash = pathTail(pszPath);
  1104. return strrchr(lastSlash ? lastSlash : pszPath, '.');
  1105. }
  1106. void removeTrailingPathSepChar(char* pszPath)
  1107. {
  1108. if (pszPath)
  1109. {
  1110. char* lastChar = pszPath + strlen(pszPath) - 1;
  1111. if (isPathSepChar(*lastChar))
  1112. *lastChar = '\0';
  1113. }
  1114. }
  1115. void stripNetAddr(const char* dir, StringBuffer& destpath, StringBuffer& destip, bool makeLinux)
  1116. {
  1117. destpath.clear().append(dir);
  1118. if (dir[0] == '\\' && dir[1] == '\\' && strlen(dir) > 2)
  1119. {
  1120. destip.clear().append(strchr(dir + 2, '\\') - (dir + 2), dir + 2);
  1121. destpath.clear().append(strchr(dir + 2, '\\'));
  1122. }
  1123. if (makeLinux)
  1124. destpath.replace('\\', '/');
  1125. }
  1126. //returns temp path that ends with path sep
  1127. //
  1128. #ifdef _WIN32
  1129. extern DWORD getLastError() { return ::GetLastError(); }
  1130. void getTempPath(char* tempPath, unsigned int bufsize, const char* subdir/*=NULL*/)
  1131. {
  1132. ::GetTempPath(bufsize, tempPath);
  1133. ::GetLongPathName(tempPath, tempPath, bufsize);
  1134. if (subdir && *subdir)
  1135. {
  1136. const int len = strlen(tempPath);
  1137. char* p = tempPath + len;
  1138. strcpy(p, subdir);
  1139. p += strlen(subdir);
  1140. *p++ = '\\';
  1141. *p = '\0';
  1142. }
  1143. }
  1144. #else//Linux specifics follow
  1145. extern DWORD getLastError() { return errno; }
  1146. void getTempPath(char* tempPath, unsigned int bufsize, const char* subdir/*=NULL*/)
  1147. {
  1148. assert(bufsize > 5);
  1149. strcpy(tempPath, "/tmp/");
  1150. if (subdir && *subdir)
  1151. {
  1152. strcat(tempPath, subdir);
  1153. strcat(tempPath, "/");
  1154. }
  1155. }
  1156. #endif