environment.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jlib.hpp"
  14. #include "environment.hpp"
  15. #include "jptree.hpp"
  16. #include "jexcept.hpp"
  17. #include "jiter.ipp"
  18. #include "jmisc.hpp"
  19. #include "jencrypt.hpp"
  20. #include "mpbase.hpp"
  21. #include "daclient.hpp"
  22. #include "dadfs.hpp"
  23. #include "dafdesc.hpp"
  24. #include "dasds.hpp"
  25. #include "dalienv.hpp"
  26. #define SDS_LOCK_TIMEOUT 10000
  27. static int environmentTraceLevel = 1;
  28. static char sEnvironmentConfFile[1024];
  29. static char sEnvironmentXMLFile[1024];
  30. static StringBuffer sEnvironmentConf;
  31. static Owned <IConstEnvironment> cache;
  32. static CDateTime confFileCacheTime;
  33. static CDateTime xmlFileCacheTime;
  34. class CConstInstanceInfo;
  35. class CLocalEnvironment : public CInterface, implements IConstEnvironment
  36. {
  37. private:
  38. // NOTE - order is important - we need to construct before p and (especially) destruct after p
  39. Owned<IRemoteConnection> conn;
  40. Owned<IPropertyTree> p;
  41. mutable MapStringToMyClass<IConstEnvBase> cache;
  42. mutable Mutex safeCache;
  43. mutable bool machineCacheBuilt;
  44. StringBuffer xPath;
  45. IConstEnvBase * getCache(const char *path) const;
  46. void setCache(const char *path, IConstEnvBase *value) const;
  47. void buildMachineCache() const;
  48. public:
  49. IMPLEMENT_IINTERFACE;
  50. CLocalEnvironment(IRemoteConnection *_conn, IPropertyTree *x=NULL, const char* path="Environment");
  51. CLocalEnvironment(const char* path="config.xml");
  52. virtual ~CLocalEnvironment();
  53. virtual IStringVal & getName(IStringVal & str) const;
  54. virtual IStringVal & getXML(IStringVal & str) const;
  55. virtual IPropertyTree & getPTree() const;
  56. virtual IEnvironment& lock() const;
  57. virtual IConstDomainInfo * getDomain(const char * name) const;
  58. virtual IConstMachineInfo * getMachine(const char * name) const;
  59. virtual IConstMachineInfo * getMachineByAddress(const char * name) const;
  60. virtual IConstInstanceInfo * getInstance(const char * type, const char * version, const char *domain) const;
  61. virtual CConstInstanceInfo * getInstanceByIP(const char *type, const char *version, IpAddress &ip) const;
  62. virtual IConstComputerTypeInfo * getComputerType(const char * name) const;
  63. virtual bool getRunInfo(IStringVal & path, IStringVal & dir, const char *type, const char *version, const char *machineaddr, const char *defprogname) const;
  64. virtual void preload();
  65. virtual IRemoteConnection* getConnection() const { return conn.getLink(); }
  66. void setXML(const char * logicalName);
  67. const char* getPath() const { return xPath.str(); }
  68. void unlockRemote();
  69. virtual bool isConstEnvironment() const { return true; }
  70. virtual void clearCache();
  71. };
  72. class CLockedEnvironment : public CInterface, implements IEnvironment
  73. {
  74. public:
  75. //note that order of construction/destruction is important
  76. Owned<CLocalEnvironment> c;
  77. Owned<CLocalEnvironment> env;
  78. Owned<CLocalEnvironment> constEnv;
  79. IMPLEMENT_IINTERFACE;
  80. CLockedEnvironment(CLocalEnvironment *_c)
  81. {
  82. Owned<IRemoteConnection> connection = _c->getConnection();
  83. if (connection)
  84. {
  85. constEnv.set(_c); //save original constant environment
  86. //we only wish to allow one party to allow updating the environment.
  87. //
  88. //create a new /NewEnvironment subtree, locked for read/write access for self and entire subtree; delete on disconnect
  89. //
  90. StringBuffer newName("/New");
  91. newName.append(constEnv->getPath());
  92. const unsigned int mode = RTM_CREATE | RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE |
  93. RTM_LOCK_SUB | RTM_DELETE_ON_DISCONNECT;
  94. Owned<IRemoteConnection> conn = querySDS().connect(newName.str(), myProcessSession(), mode, SDS_LOCK_TIMEOUT);
  95. if (conn == NULL)
  96. {
  97. if (environmentTraceLevel > 0)
  98. PrintLog("Failed to create locked environment %s", newName.str());
  99. throw MakeStringException(-1, "Failed to get a lock on environment /%s", newName.str());
  100. }
  101. //save the locked environment
  102. env.setown(new CLocalEnvironment(conn, NULL, newName.str()));
  103. //get a lock on the const environment
  104. const unsigned int mode2 = RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE | RTM_LOCK_SUB;
  105. Owned<IRemoteConnection> conn2 = querySDS().connect(constEnv->getPath(), myProcessSession(), mode2, SDS_LOCK_TIMEOUT);
  106. if (conn2 == NULL)
  107. {
  108. if (environmentTraceLevel > 0)
  109. PrintLog("Failed to lock environment %s", constEnv->getPath());
  110. throw MakeStringException(-1, "Failed to get a lock on environment /%s", constEnv->getPath());
  111. }
  112. //copy const environment to our member environment
  113. Owned<IPropertyTree> pSrc = conn2->getRoot();
  114. c.setown( new CLocalEnvironment(NULL, createPTreeFromIPT(pSrc)));
  115. conn2->rollback();
  116. }
  117. else
  118. {
  119. c.set(_c);
  120. }
  121. }
  122. virtual ~CLockedEnvironment()
  123. {
  124. }
  125. virtual IStringVal & getName(IStringVal & str) const
  126. { return c->getName(str); }
  127. virtual IStringVal & getXML(IStringVal & str) const
  128. { return c->getXML(str); }
  129. virtual IPropertyTree & getPTree() const
  130. {
  131. return c->getPTree();
  132. }
  133. virtual IConstDomainInfo * getDomain(const char * name) const
  134. { return c->getDomain(name); }
  135. virtual IConstMachineInfo * getMachine(const char * name) const
  136. { return c->getMachine(name); }
  137. virtual IConstMachineInfo * getMachineByAddress(const char * name) const
  138. { return c->getMachineByAddress(name); }
  139. virtual IConstInstanceInfo * getInstance(const char *type, const char *version, const char *domain) const
  140. { return c->getInstance(type, version, domain); }
  141. virtual bool getRunInfo(IStringVal & path, IStringVal & dir, const char *type, const char *version, const char *machineaddr,const char *defprogname) const
  142. { return c->getRunInfo(path, dir, type, version, machineaddr, defprogname); }
  143. virtual IConstComputerTypeInfo * getComputerType(const char * name) const
  144. { return c->getComputerType(name); }
  145. virtual IEnvironment & lock() const
  146. { ((CInterface*)this)->Link(); return *(IEnvironment*)this; }
  147. virtual void commit();
  148. virtual void rollback();
  149. virtual void setXML(const char * pstr)
  150. { c->setXML(pstr); }
  151. virtual void preload()
  152. { c->preload(); }
  153. virtual bool isConstEnvironment() const { return false; }
  154. virtual void clearCache() { c->clearCache(); }
  155. };
  156. void CLockedEnvironment::commit()
  157. {
  158. if (constEnv)
  159. {
  160. //get a lock on const environment momentarily
  161. const unsigned int mode2 = RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE | RTM_LOCK_SUB;
  162. Owned<IRemoteConnection> conn2 = querySDS().connect(constEnv->getPath(), myProcessSession(), mode2, SDS_LOCK_TIMEOUT);
  163. if (conn2 == NULL)
  164. {
  165. if (environmentTraceLevel > 0)
  166. PrintLog("Failed to lock environment %s", constEnv->getPath());
  167. throw MakeStringException(-1, "Failed to get a lock on environment /%s", constEnv->getPath());
  168. }
  169. //copy locked environment to const environment
  170. Owned<IPropertyTree> pSrc = &getPTree();
  171. Owned<IPropertyTree> pDst = conn2->queryRoot()->getBranch(NULL);
  172. // JCS - I think it could (and would be more efficient if it had kept the original read lock connection to Env
  173. // - instead of using NewEnv as lock point, still work on copy, then changeMode of original connect
  174. // - as opposed to current scheme, where it recoonects in write mode and has to lazy fetch original env to update.
  175. // ensures pDst is equal to pSrc, whilst minimizing changes to pDst
  176. try { synchronizePTree(pDst, pSrc); }
  177. catch (IException *) { conn2->rollback(); throw; }
  178. conn2->commit();
  179. }
  180. else
  181. {
  182. Owned<IRemoteConnection> conn = c->getConnection();
  183. conn->commit();
  184. }
  185. }
  186. void CLockedEnvironment::rollback()
  187. {
  188. if (constEnv)
  189. {
  190. //get a lock on const environment momentarily
  191. const unsigned int mode2 = RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE | RTM_LOCK_SUB;
  192. Owned<IRemoteConnection> conn2 = querySDS().connect(constEnv->getPath(), myProcessSession(), mode2, SDS_LOCK_TIMEOUT);
  193. if (conn2 == NULL)
  194. {
  195. if (environmentTraceLevel > 0)
  196. PrintLog("Failed to lock environment %s", constEnv->getPath());
  197. throw MakeStringException(-1, "Failed to get a lock on environment /%s", constEnv->getPath());
  198. }
  199. //copy const environment to locked environment (as it stands now) again losing any changes we made
  200. Owned<IPropertyTree> pSrc = conn2->getRoot();
  201. Owned<IPropertyTree> pDst = &getPTree();
  202. pDst->removeTree( pDst->queryPropTree("Hardware") );
  203. pDst->removeTree( pDst->queryPropTree("Software") );
  204. pDst->removeTree( pDst->queryPropTree("Programs") );
  205. pDst->removeTree( pDst->queryPropTree("Data") );
  206. mergePTree(pDst, pSrc);
  207. conn2->rollback();
  208. }
  209. else
  210. {
  211. Owned<IRemoteConnection> conn = c->getConnection();
  212. conn->rollback();
  213. }
  214. }
  215. //==========================================================================================
  216. // the following class implements notification handler for subscription to dali for environment
  217. // updates by other clients and is used by environment factory below. This also serves as
  218. // a sample self-contained implementation that can be easily tailored for other purposes.
  219. //==========================================================================================
  220. class CSdsSubscription : public CInterface, implements ISDSSubscription
  221. {
  222. public:
  223. CSdsSubscription()
  224. {
  225. m_constEnvUpdated = false;
  226. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory();
  227. sub_id = envFactory->subscribe(this);
  228. }
  229. virtual ~CSdsSubscription()
  230. {
  231. /* note that ideally, we would make this class automatically
  232. unsubscribe in this destructor. However, underlying dali client
  233. layer (CDaliSubscriptionManagerStub) links to this object and so
  234. object would not get destroyed just by an application releasing it.
  235. The application either needs to explicitly unsubscribe or close
  236. the environment which unsubscribes during close down. */
  237. }
  238. void unsubscribe()
  239. {
  240. synchronized block(m_mutexEnv);
  241. if (sub_id)
  242. {
  243. Owned<IEnvironmentFactory> m_envFactory = getEnvironmentFactory();
  244. m_envFactory->unsubscribe(sub_id);
  245. sub_id = 0;
  246. }
  247. }
  248. IMPLEMENT_IINTERFACE;
  249. //another client (like configenv) may have updated the environment and we got notified
  250. //(thanks to our subscription) but don't just reload it yet since this notification is sent on
  251. //another thread asynchronously and we may be actively working with the old environment. Just
  252. //invoke handleEnvironmentChange() when we are ready to invalidate cache in environment factory.
  253. //
  254. void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen=0, const void *valueData=NULL)
  255. {
  256. DBGLOG("Environment was updated by another client of Dali server. Invalidating cache.\n");
  257. synchronized block(m_mutexEnv);
  258. m_constEnvUpdated = true;
  259. }
  260. void handleEnvironmentChange()
  261. {
  262. synchronized block(m_mutexEnv);
  263. if (m_constEnvUpdated)
  264. {
  265. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory();
  266. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  267. constEnv->clearCache();
  268. m_constEnvUpdated = false;
  269. }
  270. }
  271. private:
  272. SubscriptionId sub_id;
  273. Mutex m_mutexEnv;
  274. bool m_constEnvUpdated;
  275. };
  276. //==========================================================================================
  277. class CEnvironmentFactory : public CInterface,
  278. implements IEnvironmentFactory, implements IDaliClientShutdown
  279. {
  280. public:
  281. IMPLEMENT_IINTERFACE;
  282. MAKEValueArray(SubscriptionId, SubscriptionIDs);
  283. SubscriptionIDs subIDs;
  284. Mutex mutex;
  285. Owned<CSdsSubscription> subscription;
  286. CEnvironmentFactory()
  287. {
  288. }
  289. virtual void clientShutdown();
  290. virtual ~CEnvironmentFactory()
  291. {
  292. close(); //just in case it was not explicitly closed
  293. }
  294. //Create the first environment cache from a file
  295. virtual IConstEnvironment* createEnvironmentByFile(const char* environmentConfFile, const char* environmentXMLFile)
  296. {
  297. sEnvironmentConfFile[0] = 0;
  298. sEnvironmentXMLFile[0] = 0;
  299. sEnvironmentConf.clear();
  300. if (environmentConfFile && *environmentConfFile)
  301. {
  302. strcpy(sEnvironmentConfFile, environmentConfFile);
  303. IFile * pFile = createIFile(sEnvironmentConfFile);
  304. if (pFile->exists( ))
  305. {
  306. CDateTime fcreated, fmodified, faccessed;
  307. if (pFile->getTime(&fcreated, &fmodified, &faccessed))
  308. {
  309. xmlFileCacheTime = fmodified;
  310. Owned<IFileIO> pFileIO = pFile->openShared(IFOread, IFSHfull);
  311. if (pFileIO)
  312. {
  313. StringBuffer tmpBuf;
  314. offset_t fileSize = pFile->size();
  315. tmpBuf.ensureCapacity((unsigned)fileSize);
  316. tmpBuf.setLength((unsigned)fileSize);
  317. size32_t nRead = pFileIO->read(0, (size32_t) fileSize, (char*)tmpBuf.str());
  318. if (nRead == fileSize)
  319. {
  320. sEnvironmentConf = tmpBuf;
  321. }
  322. }
  323. }
  324. }
  325. }
  326. if (!environmentXMLFile || !*environmentXMLFile)
  327. return NULL;
  328. strcpy(sEnvironmentXMLFile, environmentXMLFile);
  329. IFile * ifile = createIFile(sEnvironmentXMLFile);
  330. if (!ifile->exists( ))
  331. return NULL;
  332. CDateTime fcreated, fmodified, faccessed;
  333. if (!ifile->getTime(&fcreated, &fmodified, &faccessed))
  334. return NULL;
  335. xmlFileCacheTime = fmodified;
  336. cache.setown(new CLocalEnvironment(sEnvironmentXMLFile));
  337. return cache.getLink();
  338. }
  339. virtual const char* getEnvironmentConf()
  340. {
  341. if (!sEnvironmentConfFile || !*sEnvironmentConfFile)
  342. return NULL;
  343. IFile * pFile = createIFile(sEnvironmentConfFile);
  344. if (pFile->exists( ))
  345. {
  346. CDateTime fcreated, fmodified, faccessed;
  347. if (pFile->getTime(&fcreated, &fmodified, &faccessed))
  348. {
  349. if ((sEnvironmentConf.length() < 1) || (xmlFileCacheTime != fmodified))
  350. {
  351. xmlFileCacheTime = fmodified;
  352. Owned<IFileIO> pFileIO = pFile->openShared(IFOread, IFSHfull);
  353. if (pFileIO)
  354. {
  355. StringBuffer tmpBuf;
  356. offset_t fileSize = pFile->size();
  357. tmpBuf.ensureCapacity((unsigned)fileSize);
  358. tmpBuf.setLength((unsigned)fileSize);
  359. size32_t nRead = pFileIO->read(0, (size32_t) fileSize, (char*)tmpBuf.str());
  360. if (nRead == fileSize)
  361. {
  362. sEnvironmentConf = tmpBuf;
  363. }
  364. }
  365. }
  366. }
  367. }
  368. return sEnvironmentConf.str();
  369. }
  370. virtual IConstEnvironment* openEnvironmentByFile()
  371. {
  372. //For cackward compatible
  373. if (!sEnvironmentXMLFile || !*sEnvironmentXMLFile)
  374. return openEnvironment();
  375. synchronized procedure(mutex);
  376. IFile * ifile = createIFile(sEnvironmentXMLFile);
  377. if (!ifile->exists( ))
  378. return openEnvironment();
  379. CDateTime fcreated, fmodified, faccessed;
  380. if (!ifile->getTime(&fcreated, &fmodified, &faccessed))
  381. return openEnvironment();
  382. if (!cache || (xmlFileCacheTime != fmodified))
  383. {
  384. xmlFileCacheTime = fmodified;
  385. cache.setown(new CLocalEnvironment(sEnvironmentXMLFile));
  386. }
  387. return cache.getLink();
  388. }
  389. virtual IConstEnvironment* openEnvironment()
  390. {
  391. synchronized procedure(mutex);
  392. if (!cache)
  393. {
  394. Owned<IRemoteConnection> conn = querySDS().connect("/Environment", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  395. if (conn)
  396. cache.setown(new CLocalEnvironment(conn));
  397. }
  398. return cache.getLink();
  399. }
  400. virtual IEnvironment* updateEnvironment()
  401. {
  402. Owned<IConstEnvironment> pConstEnv = openEnvironment();
  403. synchronized procedure(mutex);
  404. return &pConstEnv->lock();
  405. }
  406. virtual IEnvironment * loadLocalEnvironmentFile(const char * filename)
  407. {
  408. Owned<IPropertyTree> ptree = createPTreeFromXMLFile(filename);
  409. Owned<CLocalEnvironment> pLocalEnv = new CLocalEnvironment(NULL, ptree);
  410. return new CLockedEnvironment(pLocalEnv);
  411. }
  412. virtual IEnvironment * loadLocalEnvironment(const char * xml)
  413. {
  414. Owned<IPropertyTree> ptree = createPTreeFromXMLString(xml);
  415. Owned<CLocalEnvironment> pLocalEnv = new CLocalEnvironment(NULL, ptree);
  416. return new CLockedEnvironment(pLocalEnv);
  417. }
  418. void close()
  419. {
  420. SubscriptionIDs copySubIDs;
  421. {
  422. synchronized procedure(mutex);
  423. cache.clear();
  424. //save the active subscriptions in another array
  425. //so they can be unsubscribed without causing deadlock
  426. // since ~CSdsSubscription() would ask us to unsubscribe the
  427. //same requiring a mutex lock (copy is a little price for this
  428. //normally small/empty array).
  429. //
  430. ForEachItemIn(i, subIDs)
  431. copySubIDs.append(subIDs.item(i));
  432. subIDs.kill();
  433. }
  434. //now unsubscribe all outstanding subscriptions
  435. //
  436. subscription.clear();
  437. ForEachItemIn(i, copySubIDs)
  438. querySDS().unsubscribe( copySubIDs.item(i) );
  439. }
  440. virtual SubscriptionId subscribe(ISDSSubscription* pSubHandler)
  441. {
  442. SubscriptionId sub_id = querySDS().subscribe("/Environment", *pSubHandler);
  443. synchronized procedure(mutex);
  444. subIDs.append(sub_id);
  445. return sub_id;
  446. }
  447. virtual void unsubscribe(SubscriptionId sub_id)
  448. {
  449. synchronized procedure(mutex);
  450. aindex_t i = subIDs.find(sub_id);
  451. if (i != NotFound)
  452. {
  453. querySDS().unsubscribe(sub_id);
  454. subIDs.remove(i);
  455. }
  456. }
  457. virtual void validateCache()
  458. {
  459. if (!subscription)
  460. subscription.setown( new CSdsSubscription() );
  461. subscription->handleEnvironmentChange();
  462. }
  463. private:
  464. IRemoteConnection* connect(const char *xpath, unsigned flags)
  465. {
  466. return querySDS().connect(xpath, myProcessSession(), flags, SDS_LOCK_TIMEOUT);
  467. }
  468. };
  469. static CEnvironmentFactory *factory=NULL;
  470. void CEnvironmentFactory::clientShutdown()
  471. {
  472. closeEnvironment();
  473. }
  474. MODULE_INIT(INIT_PRIORITY_ENV_ENVIRONMENT)
  475. {
  476. return true;
  477. }
  478. MODULE_EXIT()
  479. {
  480. ::Release(factory);
  481. }
  482. //==========================================================================================
  483. class CConstEnvBase : public CInterface
  484. {
  485. protected:
  486. const CLocalEnvironment* env; // Not linked - would be circular....
  487. // That could cause problems
  488. Linked<IPropertyTree> root;
  489. public:
  490. CConstEnvBase(const CLocalEnvironment* _env, IPropertyTree *_root)
  491. : env(_env), root(_root)
  492. {
  493. }
  494. IStringVal& getXML(IStringVal &str) const
  495. {
  496. StringBuffer x;
  497. toXML(root->queryBranch("."), x);
  498. str.set(x.str());
  499. return str;
  500. };
  501. IStringVal& getName(IStringVal &str) const
  502. {
  503. str.set(root->queryProp("@name"));
  504. return str;
  505. }
  506. IPropertyTree& getPTree() const
  507. {
  508. return *LINK(root);
  509. }
  510. };
  511. #define IMPLEMENT_ICONSTENVBASE \
  512. virtual IStringVal& getXML(IStringVal &str) const { return CConstEnvBase::getXML(str); } \
  513. virtual IStringVal& getName(IStringVal &str) const { return CConstEnvBase::getName(str); } \
  514. virtual IPropertyTree& getPTree() const { return CConstEnvBase::getPTree(); }
  515. //==========================================================================================
  516. class CConstDomainInfo : public CConstEnvBase, implements IConstDomainInfo
  517. {
  518. public:
  519. IMPLEMENT_IINTERFACE;
  520. IMPLEMENT_ICONSTENVBASE;
  521. CConstDomainInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root) {}
  522. virtual void getAccountInfo(IStringVal &name, IStringVal &pw) const
  523. {
  524. if (root->hasProp("@username"))
  525. name.set(root->queryProp("@username"));
  526. else
  527. name.clear();
  528. if (root->hasProp("@password"))
  529. {
  530. StringBuffer pwd;
  531. decrypt(pwd, root->queryProp("@password"));
  532. pw.set(pwd.str());
  533. }
  534. else
  535. pw.clear();
  536. }
  537. virtual void getSnmpSecurityString(IStringVal & securityString) const
  538. {
  539. if (root->hasProp("@snmpSecurityString"))
  540. {
  541. StringBuffer sec_string;
  542. decrypt(sec_string, root->queryProp("@snmpSecurityString"));
  543. securityString.set(sec_string.str());
  544. }
  545. else
  546. securityString.set("");
  547. }
  548. virtual void getSSHAccountInfo(IStringVal &name, IStringVal &sshKeyFile, IStringVal& sshKeyPassphrase) const
  549. {
  550. if (root->hasProp("@username"))
  551. name.set(root->queryProp("@username"));
  552. else
  553. name.clear();
  554. if (root->hasProp("@sshKeyFile"))
  555. sshKeyFile.set(root->queryProp("@sshKeyFile"));
  556. else
  557. sshKeyFile.clear();
  558. if (root->hasProp("@sshKeyPassphrase"))
  559. sshKeyPassphrase.set(root->queryProp("@sshKeyPassphrase"));
  560. else
  561. sshKeyPassphrase.clear();
  562. }
  563. };
  564. //==========================================================================================
  565. struct mapEnums { EnvMachineOS val; const char *str; };
  566. static EnvMachineOS getEnum(IPropertyTree *p, const char *propname, mapEnums *map)
  567. {
  568. const char *v = p->queryProp(propname);
  569. if (v && *v)
  570. {
  571. while (map->str)
  572. {
  573. if (stricmp(v, map->str)==0)
  574. return map->val;
  575. map++;
  576. }
  577. throw MakeStringException(0, "Unknown operating system: \"%s\"", v);
  578. }
  579. return MachineOsUnknown;
  580. }
  581. struct mapStateEnums { EnvMachineState val; const char *str; };
  582. static EnvMachineState getEnum(IPropertyTree *p, const char *propname, mapStateEnums *map)
  583. {
  584. const char *v = p->queryProp(propname);
  585. if (v && *v)
  586. {
  587. while (map->str)
  588. {
  589. if (stricmp(v, map->str)==0)
  590. return map->val;
  591. map++;
  592. }
  593. assertex(!"Unexpected value in getEnum");
  594. }
  595. return MachineStateUnknown;
  596. }
  597. mapEnums OperatingSystems[] = {
  598. { MachineOsW2K, "W2K" },
  599. { MachineOsSolaris, "solaris" },
  600. { MachineOsLinux, "linux" },
  601. { MachineOsSize, NULL }
  602. };
  603. mapStateEnums MachineStates[] = {
  604. { MachineStateAvailable, "Available" },
  605. { MachineStateUnavailable, "Unavailable" },
  606. { MachineStateUnknown, "Unknown" }
  607. };
  608. //==========================================================================================
  609. class CConstMachineInfo : public CConstEnvBase, implements IConstMachineInfo
  610. {
  611. public:
  612. IMPLEMENT_IINTERFACE;
  613. IMPLEMENT_ICONSTENVBASE;
  614. CConstMachineInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root) {}
  615. virtual IConstDomainInfo* getDomain() const
  616. {
  617. return env->getDomain(root->queryProp("@domain"));
  618. }
  619. virtual IStringVal& getNetAddress(IStringVal &str) const
  620. {
  621. str.set(root->queryProp("@netAddress"));
  622. return str;
  623. }
  624. virtual IStringVal& getDescription(IStringVal &str) const
  625. {
  626. UNIMPLEMENTED;
  627. }
  628. virtual unsigned getNicSpeedMbitSec() const
  629. {
  630. const char * v = root->queryProp("@nicSpeed");
  631. if (v && *v)
  632. return atoi(v);
  633. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  634. if (type)
  635. return type->getNicSpeedMbitSec();
  636. return 0;
  637. }
  638. virtual EnvMachineOS getOS() const
  639. {
  640. EnvMachineOS os = getEnum(root, "@opSys", OperatingSystems);
  641. if (os != MachineOsUnknown)
  642. return os;
  643. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  644. if (type)
  645. return type->getOS();
  646. return MachineOsUnknown;
  647. }
  648. virtual EnvMachineState getState() const
  649. {
  650. return getEnum(root, "@state", MachineStates);
  651. }
  652. };
  653. //==========================================================================================
  654. class CConstComputerTypeInfo : public CConstEnvBase, implements IConstComputerTypeInfo
  655. {
  656. public:
  657. IMPLEMENT_IINTERFACE;
  658. IMPLEMENT_ICONSTENVBASE;
  659. CConstComputerTypeInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root) {}
  660. virtual EnvMachineOS getOS() const
  661. {
  662. EnvMachineOS os = getEnum(root, "@opSys", OperatingSystems);
  663. if (os != MachineOsUnknown)
  664. return os;
  665. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  666. if (type)
  667. return type->getOS();
  668. return MachineOsUnknown;
  669. }
  670. virtual unsigned getNicSpeedMbitSec() const
  671. {
  672. const char * v = root->queryProp("@nicSpeed");
  673. if (v && *v)
  674. return atoi(v);
  675. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  676. if (type)
  677. return type->getNicSpeedMbitSec();
  678. return 0;
  679. }
  680. };
  681. //==========================================================================================
  682. class CConstInstanceInfo : public CConstEnvBase, implements IConstInstanceInfo
  683. {
  684. public:
  685. IMPLEMENT_IINTERFACE;
  686. IMPLEMENT_ICONSTENVBASE;
  687. CConstInstanceInfo(const CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root)
  688. {
  689. }
  690. virtual IConstMachineInfo * getMachine() const
  691. {
  692. return env->getMachine(root->queryProp("@computer"));
  693. }
  694. virtual IStringVal & getEndPoint(IStringVal & str) const
  695. {
  696. SCMStringBuffer ep;
  697. Owned<IConstMachineInfo> machine = getMachine();
  698. if (machine)
  699. {
  700. machine->getNetAddress(ep);
  701. const char *port = root->queryProp("@port");
  702. if (port)
  703. ep.s.append(':').append(port);
  704. }
  705. str.set(ep.str());
  706. return str;
  707. }
  708. virtual IStringVal & getExecutableDirectory(IStringVal & str) const
  709. {
  710. // this is the deploy directory so uses local path separators (I suspect this call is LEGACY now)
  711. SCMStringBuffer ep;
  712. Owned<IConstMachineInfo> machine = getMachine();
  713. if (machine)
  714. {
  715. machine->getNetAddress(ep);
  716. ep.s.insert(0, PATHSEPSTR PATHSEPSTR);
  717. }
  718. ep.s.append(PATHSEPCHAR).append(root->queryProp("@directory"));
  719. str.set(ep.str());
  720. return str;
  721. }
  722. virtual bool doGetRunInfo(IStringVal & progpath, IStringVal & workdir, const char *defprogname, bool useprog) const
  723. {
  724. // this is remote path i.e. path should match *target* nodes format
  725. Owned<IConstMachineInfo> machine = getMachine();
  726. if (!machine)
  727. return false;
  728. char psep;
  729. bool appendexe;
  730. switch (machine->getOS()) {
  731. case MachineOsSolaris:
  732. case MachineOsLinux:
  733. psep = '/';
  734. appendexe = false;
  735. break;
  736. default:
  737. psep = '\\';
  738. appendexe = true;
  739. }
  740. StringBuffer tmp;
  741. const char *program = useprog?root->queryProp("@program"):NULL; // if program specified assume absolute
  742. if (!program||!*program) {
  743. SCMStringBuffer ep;
  744. machine->getNetAddress(ep);
  745. const char *dir = root->queryProp("@directory");
  746. if (dir) {
  747. if (isPathSepChar(*dir))
  748. dir++;
  749. if (!*dir)
  750. return false;
  751. tmp.append(psep).append(psep).append(ep.s).append(psep);
  752. do {
  753. if (isPathSepChar(*dir))
  754. tmp.append(psep);
  755. else
  756. tmp.append(*dir);
  757. dir++;
  758. } while (*dir);
  759. if (!isPathSepChar(tmp.charAt(tmp.length()-1)))
  760. tmp.append(psep);
  761. tmp.append(defprogname);
  762. size32_t l = strlen(defprogname);
  763. if (appendexe&&((l<5)||(stricmp(defprogname+l-4,".exe")!=0)))
  764. tmp.append(".exe");
  765. }
  766. program = tmp.str();
  767. }
  768. progpath.set(program);
  769. const char *workd = root->queryProp("@workdir"); // if program specified assume absolute
  770. workdir.set(workd?workd:"");
  771. return true;
  772. }
  773. virtual bool getRunInfo(IStringVal & progpath, IStringVal & workdir, const char *defprogname) const
  774. {
  775. return doGetRunInfo(progpath,workdir,defprogname,true);
  776. }
  777. virtual unsigned getPort() const
  778. {
  779. return root->getPropInt("@port", 0);
  780. }
  781. };
  782. #if 0
  783. //==========================================================================================
  784. class CConstProcessInfo : public CConstEnvBase, implements IConstProcessInfo
  785. {
  786. IArrayOf<IConstInstanceInfo> w;
  787. CArrayIterator it;
  788. public:
  789. IMPLEMENT_IINTERFACE;
  790. IMPLEMENT_ICONSTENVBASE;
  791. CConstProcessInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root), it(w)
  792. {
  793. Owned<IPropertyTreeIterator> _it = root->getElements("*"); // MORE - should be instance
  794. for (_it->first(); _it->isValid(); _it->next())
  795. {
  796. IPropertyTree *rp = &_it->query();
  797. w.append(*new CConstInstanceInfo(env, rp)); // CConstInstanceInfo will link rp
  798. }
  799. }
  800. bool first() { return it.first(); }
  801. bool isValid() { return it.isValid(); }
  802. bool next() { return it.next(); }
  803. IConstInstanceInfo & query() { return (IConstInstanceInfo &) it.query();}
  804. virtual IConstInstanceInfo * getInstance(const char *domain)
  805. {
  806. for (int pass=0; pass<2; pass++)
  807. ForEachItemIn(idx, w)
  808. {
  809. Owned<IConstMachineInfo> m = w.item(idx).getMachine();
  810. if (m)
  811. {
  812. Owned<IConstDomainInfo> dm = m->getDomain();
  813. if (dm)
  814. {
  815. StringBuffer thisdomain;
  816. //dm->getName(StringBufferAdaptor(thisdomain)); // confuses g++
  817. StringBufferAdaptor strval(thisdomain);
  818. dm->getName(strval);
  819. if (thisdomain.length() && strcmp(domain, thisdomain.str())==0)
  820. return LINK(&w.item(idx));
  821. }
  822. }
  823. }
  824. return NULL;
  825. }
  826. };
  827. #endif
  828. //==========================================================================================
  829. CLocalEnvironment::CLocalEnvironment(const char* environmentFile)
  830. {
  831. if (environmentFile && *environmentFile)
  832. {
  833. IPropertyTree* root = createPTreeFromXMLFile(environmentFile);
  834. if (root)
  835. p.set(root);
  836. }
  837. machineCacheBuilt = false;
  838. }
  839. CLocalEnvironment::CLocalEnvironment(IRemoteConnection *_conn, IPropertyTree* root/*=NULL*/,
  840. const char* path/*="/Environment"*/)
  841. : xPath(path)
  842. {
  843. conn.set(_conn);
  844. if (root)
  845. p.set(root);
  846. else
  847. p.setown(conn->getRoot());
  848. machineCacheBuilt = false;
  849. }
  850. CLocalEnvironment::~CLocalEnvironment()
  851. {
  852. if (conn)
  853. conn->rollback();
  854. }
  855. IEnvironment& CLocalEnvironment::lock() const
  856. {
  857. return *new CLockedEnvironment((CLocalEnvironment*)this);
  858. }
  859. IStringVal & CLocalEnvironment::getName(IStringVal & str) const
  860. {
  861. str.set(p->queryProp("@name"));
  862. return str;
  863. }
  864. IStringVal & CLocalEnvironment::getXML(IStringVal & str) const
  865. {
  866. StringBuffer xml;
  867. toXML(p->queryBranch("."), xml);
  868. str.set(xml.str());
  869. return str;
  870. }
  871. IPropertyTree & CLocalEnvironment::getPTree() const
  872. {
  873. return *LINK(p);
  874. }
  875. IConstEnvBase * CLocalEnvironment::getCache(const char *path) const
  876. {
  877. IConstEnvBase * ret = cache.getValue(path);
  878. ::Link(ret);
  879. return ret;
  880. }
  881. void CLocalEnvironment::setCache(const char *path, IConstEnvBase *value) const
  882. {
  883. cache.setValue(path, value);
  884. }
  885. IConstDomainInfo * CLocalEnvironment::getDomain(const char * name) const
  886. {
  887. if (!name)
  888. return NULL;
  889. StringBuffer xpath;
  890. xpath.appendf("Hardware/Domain[@name=\"%s\"]", name);
  891. synchronized procedure(safeCache);
  892. IConstEnvBase *cached = getCache(xpath.str());
  893. if (!cached)
  894. {
  895. IPropertyTree *d = p->queryPropTree(xpath.str());
  896. if (!d)
  897. return NULL;
  898. cached = new CConstDomainInfo((CLocalEnvironment *) this, d);
  899. setCache(xpath.str(), cached);
  900. }
  901. return (IConstDomainInfo *) cached;
  902. }
  903. void CLocalEnvironment::buildMachineCache() const
  904. {
  905. synchronized procedure(safeCache);
  906. if (!machineCacheBuilt)
  907. {
  908. Owned<IPropertyTreeIterator> it = p->getElements("Hardware/Computer");
  909. ForEach(*it)
  910. {
  911. const char *name = it->query().queryProp("@name");
  912. if (name)
  913. {
  914. StringBuffer x("Hardware/Computer[@name=\"");
  915. x.append(name).append("\"]");
  916. Owned<IConstEnvBase> cached = new CConstMachineInfo((CLocalEnvironment *) this, &it->query());
  917. cache.setValue(x.str(), cached);
  918. }
  919. name = it->query().queryProp("@netAddress");
  920. if (name)
  921. {
  922. StringBuffer x("Hardware/Computer[@netAddress=\"");
  923. x.append(name).append("\"]");
  924. Owned<IConstEnvBase> cached = new CConstMachineInfo((CLocalEnvironment *) this, &it->query());
  925. cache.setValue(x.str(), cached);
  926. }
  927. }
  928. machineCacheBuilt = true;
  929. }
  930. }
  931. IConstComputerTypeInfo * CLocalEnvironment::getComputerType(const char * name) const
  932. {
  933. if (!name)
  934. return NULL;
  935. StringBuffer xpath;
  936. xpath.appendf("Hardware/ComputerType[@name=\"%s\"]", name);
  937. synchronized procedure(safeCache);
  938. IConstEnvBase *cached = getCache(xpath.str());
  939. if (!cached)
  940. {
  941. IPropertyTree *d = p->queryPropTree(xpath.str());
  942. if (!d)
  943. return NULL;
  944. cached = new CConstComputerTypeInfo((CLocalEnvironment *) this, d);
  945. setCache(xpath.str(), cached);
  946. }
  947. return (CConstComputerTypeInfo *) cached;
  948. }
  949. IConstMachineInfo * CLocalEnvironment::getMachine(const char * name) const
  950. {
  951. if (!name)
  952. return NULL;
  953. buildMachineCache();
  954. StringBuffer xpath;
  955. xpath.appendf("Hardware/Computer[@name=\"%s\"]", name);
  956. synchronized procedure(safeCache);
  957. IConstEnvBase *cached = getCache(xpath.str());
  958. if (!cached)
  959. {
  960. IPropertyTree *d = p->queryPropTree(xpath.str());
  961. if (!d)
  962. return NULL;
  963. cached = new CConstMachineInfo((CLocalEnvironment *) this, d);
  964. setCache(xpath.str(), cached);
  965. }
  966. return (CConstMachineInfo *) cached;
  967. }
  968. IConstMachineInfo * CLocalEnvironment::getMachineByAddress(const char * name) const
  969. {
  970. if (!name)
  971. return NULL;
  972. buildMachineCache();
  973. Owned<IPropertyTreeIterator> iter;
  974. StringBuffer xpath;
  975. xpath.appendf("Hardware/Computer[@netAddress=\"%s\"]", name);
  976. synchronized procedure(safeCache);
  977. IConstEnvBase *cached = getCache(xpath.str());
  978. if (!cached)
  979. {
  980. IPropertyTree *d = p->queryPropTree(xpath.str());
  981. if (!d) {
  982. // I suspect not in the original spirit of this but look for resolved IP
  983. Owned<IPropertyTreeIterator> iter = p->getElements("Hardware/Computer");
  984. IpAddress ip;
  985. ip.ipset(name);
  986. ForEach(*iter) {
  987. IPropertyTree &computer = iter->query();
  988. IpAddress ip2;
  989. const char *ips = computer.queryProp("@netAddress");
  990. if (ips&&*ips) {
  991. ip2.ipset(ips);
  992. if (ip.ipequals(ip2)) {
  993. d = &computer;
  994. break;
  995. }
  996. }
  997. }
  998. }
  999. if (!d)
  1000. return NULL;
  1001. StringBuffer xpath1;
  1002. xpath1.appendf("Hardware/Computer[@name=\"%s\"]", d->queryProp("@name"));
  1003. cached = getCache(xpath1.str());
  1004. if (!cached)
  1005. {
  1006. cached = new CConstMachineInfo((CLocalEnvironment *) this, d);
  1007. setCache(xpath1.str(), cached);
  1008. setCache(xpath.str(), cached);
  1009. }
  1010. }
  1011. return (CConstMachineInfo *) cached;
  1012. }
  1013. IConstInstanceInfo * CLocalEnvironment::getInstance(const char *type, const char *version, const char *domain) const
  1014. {
  1015. StringBuffer xpath("Software/");
  1016. xpath.append(type);
  1017. if (version)
  1018. xpath.append("[@version='").append(version).append("']");
  1019. xpath.append("/Instance");
  1020. Owned<IPropertyTreeIterator> _it = p->getElements(xpath);
  1021. for (_it->first(); _it->isValid(); _it->next())
  1022. {
  1023. IPropertyTree *rp = &_it->query();
  1024. Owned<CConstInstanceInfo> inst = new CConstInstanceInfo(this, rp); // CConstInstanceInfo will link rp
  1025. Owned<IConstMachineInfo> m = inst->getMachine();
  1026. if (m)
  1027. {
  1028. Owned<IConstDomainInfo> dm = m->getDomain();
  1029. if (dm)
  1030. {
  1031. SCMStringBuffer thisdomain;
  1032. dm->getName(thisdomain);
  1033. if (thisdomain.length() && strcmp(domain, thisdomain.str())==0)
  1034. return inst.getClear();
  1035. }
  1036. }
  1037. }
  1038. return NULL;
  1039. }
  1040. CConstInstanceInfo * CLocalEnvironment::getInstanceByIP(const char *type, const char *version, IpAddress &ip) const
  1041. {
  1042. StringBuffer xpath("Software/");
  1043. xpath.append(type);
  1044. if (version)
  1045. xpath.append("[@version='").append(version).append("']");
  1046. xpath.append("/Instance");
  1047. assertex(p);
  1048. Owned<IPropertyTreeIterator> _it = p->getElements(xpath);
  1049. assertex(_it);
  1050. for (_it->first(); _it->isValid(); _it->next())
  1051. {
  1052. IPropertyTree *rp = &_it->query();
  1053. assertex(rp);
  1054. Owned<CConstInstanceInfo> inst = new CConstInstanceInfo(this, rp); // CConstInstanceInfo will link rp
  1055. Owned<IConstMachineInfo> m = inst->getMachine();
  1056. if (m)
  1057. {
  1058. SCMStringBuffer eps;
  1059. m->getNetAddress(eps);
  1060. SocketEndpoint ep(eps.str());
  1061. if (ep.ipequals(ip))
  1062. return inst.getClear();
  1063. }
  1064. }
  1065. return NULL;
  1066. }
  1067. void CLocalEnvironment::unlockRemote()
  1068. {
  1069. #if 0
  1070. conn->commit(true);
  1071. conn->changeMode(0, SDS_LOCK_TIMEOUT);
  1072. #else
  1073. if (conn)
  1074. {
  1075. p.clear();
  1076. conn.setown(querySDS().connect(xPath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT));
  1077. p.setown(conn->getRoot());
  1078. }
  1079. #endif
  1080. }
  1081. void CLocalEnvironment::preload()
  1082. {
  1083. p->queryBranch(".");
  1084. }
  1085. void CLocalEnvironment::setXML(const char *xml)
  1086. {
  1087. Owned<IPropertyTree> newRoot = createPTreeFromXMLString(xml);
  1088. Owned<IPropertyTreeIterator> it = p->getElements("*");
  1089. ForEach(*it)
  1090. {
  1091. p->removeTree(&it->query());
  1092. }
  1093. it.setown(newRoot->getElements("*"));
  1094. ForEach(*it)
  1095. {
  1096. IPropertyTree *sub = &it->get();
  1097. p->addPropTree(sub->queryName(), sub);
  1098. }
  1099. }
  1100. bool CLocalEnvironment::getRunInfo(IStringVal & path, IStringVal & dir, const char * tag, const char * version, const char *machineaddr, const char *defprogname) const
  1101. {
  1102. try
  1103. {
  1104. // PrintLog("getExecutablePath %s %s %s", tag, version, machineaddr);
  1105. // first see if local machine with deployed on
  1106. SocketEndpoint ep(machineaddr);
  1107. Owned<CConstInstanceInfo> ipinstance = getInstanceByIP(tag, version, ep);
  1108. if (ipinstance)
  1109. {
  1110. StringAttr testpath;
  1111. StringAttrAdaptor teststrval(testpath);
  1112. if (ipinstance->doGetRunInfo(teststrval,dir,defprogname,false)) { // this returns full string
  1113. RemoteFilename rfn;
  1114. rfn.setRemotePath(testpath.get());
  1115. Owned<IFile> file = createIFile(rfn);
  1116. if (file->exists()) {
  1117. StringBuffer tmp;
  1118. rfn.getLocalPath(tmp);
  1119. path.set(tmp.str());
  1120. return true;
  1121. }
  1122. }
  1123. }
  1124. Owned<IConstMachineInfo> machine = getMachineByAddress(machineaddr);
  1125. if (!machine)
  1126. {
  1127. LOG(MCdebugInfo, unknownJob, "Unable to find machine for %s", machineaddr);
  1128. return false;
  1129. }
  1130. StringAttr targetdomain;
  1131. Owned<IConstDomainInfo> domain = machine->getDomain();
  1132. if (!domain)
  1133. {
  1134. LOG(MCdebugInfo, unknownJob, "Unable to find domain for %s", machineaddr);
  1135. return false;
  1136. }
  1137. //domain->getName(StringAttrAdaptor(targetdomain)); // confuses g++
  1138. StringAttrAdaptor strval(targetdomain);
  1139. domain->getName(strval);
  1140. Owned<IConstInstanceInfo> instance = getInstance(tag, version, targetdomain);
  1141. if (!instance)
  1142. {
  1143. LOG(MCdebugInfo, unknownJob, "Unable to find process %s for domain %s", tag, targetdomain.get());
  1144. return false;
  1145. }
  1146. return instance->getRunInfo(path,dir,defprogname);
  1147. }
  1148. catch (IException * e)
  1149. {
  1150. EXCLOG(e, "Extracting slave version");
  1151. e->Release();
  1152. return false;
  1153. }
  1154. }
  1155. void CLocalEnvironment::clearCache()
  1156. {
  1157. synchronized procedure(safeCache);
  1158. if (conn) {
  1159. p.clear();
  1160. conn->reload();
  1161. p.setown(conn->getRoot());
  1162. }
  1163. cache.kill();
  1164. machineCacheBuilt = false;
  1165. resetPasswordsFromSDS();
  1166. }
  1167. //==========================================================================================
  1168. static CriticalSection getEnvSect;
  1169. extern ENVIRONMENT_API IEnvironmentFactory * getEnvironmentFactory()
  1170. {
  1171. CriticalBlock block(getEnvSect);
  1172. if (!factory)
  1173. {
  1174. factory = new CEnvironmentFactory();
  1175. addShutdownHook(*factory);
  1176. }
  1177. return LINK(factory);
  1178. }
  1179. extern ENVIRONMENT_API void closeEnvironment()
  1180. {
  1181. try
  1182. {
  1183. CEnvironmentFactory* pFactory;
  1184. {
  1185. //this method is not meant to be invoked by multiple
  1186. //threads concurrently but just in case...
  1187. CriticalBlock block(getEnvSect);
  1188. pFactory = factory;
  1189. factory = NULL;
  1190. }
  1191. clearPasswordsFromSDS();
  1192. if (pFactory)
  1193. {
  1194. removeShutdownHook(*pFactory);
  1195. pFactory->close();
  1196. pFactory->Release();
  1197. }
  1198. }
  1199. catch (IException *e)
  1200. {
  1201. EXCLOG(e);
  1202. }
  1203. }