environment.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871
  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 30000
  27. #define DEFAULT_DROPZONE_INDEX 1
  28. #define DROPZONE_BY_MACHINE_SUFFIX "-dropzoneByMachine-"
  29. #define DROPZONE_SUFFIX "dropzone-"
  30. #define MACHINE_PREFIX "machine-"
  31. static int environmentTraceLevel = 1;
  32. static Owned <IConstEnvironment> cache;
  33. class CLocalEnvironment;
  34. class CConstMachineInfoIterator : public CSimpleInterfaceOf<IConstMachineInfoIterator>
  35. {
  36. public:
  37. CConstMachineInfoIterator();
  38. virtual bool first() override;
  39. virtual bool next() override;
  40. virtual bool isValid() override;
  41. virtual IConstMachineInfo & query() override;
  42. virtual unsigned count() const override;
  43. protected:
  44. Owned<IConstMachineInfo> curr;
  45. Owned<CLocalEnvironment> constEnv;
  46. unsigned index = 1;
  47. unsigned maxIndex = 0;
  48. };
  49. class CConstDropZoneServerInfoIterator : public CSimpleInterfaceOf<IConstDropZoneServerInfoIterator>
  50. {
  51. public:
  52. CConstDropZoneServerInfoIterator(const IConstDropZoneInfo * dropZone);
  53. virtual bool first() override;
  54. virtual bool next() override;
  55. virtual bool isValid() override;
  56. virtual IConstDropZoneServerInfo & query() override;
  57. virtual unsigned count() const override;
  58. protected:
  59. Owned<IConstDropZoneServerInfo> curr;
  60. Owned<CLocalEnvironment> constEnv;
  61. Owned<IPropertyTreeIterator> serverListIt;
  62. unsigned maxIndex = 0;
  63. };
  64. class CConstDropZoneInfoIterator : public CSimpleInterfaceOf<IConstDropZoneInfoIterator>
  65. {
  66. public:
  67. CConstDropZoneInfoIterator();
  68. virtual bool first() override;
  69. virtual bool next() override;
  70. virtual bool isValid() override;
  71. virtual IConstDropZoneInfo & query() override;
  72. virtual unsigned count() const override;
  73. protected:
  74. Owned<IConstDropZoneInfo> curr;
  75. Owned<CLocalEnvironment> constEnv;
  76. unsigned index = 1;
  77. unsigned maxIndex = 0;
  78. };
  79. //==========================================================================================
  80. class CConstInstanceInfo;
  81. class CLocalEnvironment : implements IConstEnvironment, public CInterface
  82. {
  83. private:
  84. // NOTE - order is important - we need to construct before p and (especially) destruct after p
  85. Owned<IRemoteConnection> conn;
  86. Owned<IPropertyTree> p;
  87. mutable MapStringToMyClass<IConstEnvBase> cache;
  88. mutable Mutex safeCache;
  89. mutable bool dropZoneCacheBuilt;
  90. mutable bool machineCacheBuilt;
  91. StringBuffer xPath;
  92. mutable unsigned numOfMachines;
  93. mutable unsigned numOfDropZones;
  94. IConstEnvBase * getCache(const char *path) const;
  95. void setCache(const char *path, IConstEnvBase *value) const;
  96. void buildMachineCache() const;
  97. void buildDropZoneCache() const;
  98. void init();
  99. mutable bool isDropZoneRestrictionLoaded = false;
  100. mutable bool dropZoneRestrictionEnabled = true;
  101. public:
  102. IMPLEMENT_IINTERFACE;
  103. CLocalEnvironment(IRemoteConnection *_conn, IPropertyTree *x=nullptr, const char* path="Environment");
  104. CLocalEnvironment(const char* path="config.xml");
  105. virtual ~CLocalEnvironment();
  106. virtual IStringVal & getName(IStringVal & str) const;
  107. virtual IStringVal & getXML(IStringVal & str) const;
  108. virtual IPropertyTree & getPTree() const;
  109. virtual IEnvironment& lock() const;
  110. virtual IConstDomainInfo * getDomain(const char * name) const;
  111. virtual IConstMachineInfo * getMachine(const char * name) const;
  112. virtual IConstMachineInfo * getMachineByAddress(const char * machineIp) const;
  113. virtual IConstMachineInfo * getMachineForLocalHost() const;
  114. virtual IConstDropZoneInfo * getDropZone(const char * name) const;
  115. virtual IConstInstanceInfo * getInstance(const char * type, const char * version, const char *domain) const;
  116. virtual CConstInstanceInfo * getInstanceByIP(const char *type, const char *version, IpAddress &ip) const;
  117. virtual IConstComputerTypeInfo * getComputerType(const char * name) const;
  118. virtual bool getRunInfo(IStringVal & path, IStringVal & dir, const char *type, const char *version, const char *machineaddr, const char *defprogname) const;
  119. virtual void preload();
  120. virtual IRemoteConnection* getConnection() const { return conn.getLink(); }
  121. void setXML(const char * logicalName);
  122. const char* getPath() const { return xPath.str(); }
  123. void unlockRemote();
  124. virtual bool isConstEnvironment() const { return true; }
  125. virtual void clearCache();
  126. virtual IConstMachineInfoIterator * getMachineIterator() const;
  127. virtual IConstDropZoneInfoIterator * getDropZoneIteratorByAddress(const char * address) const;
  128. virtual IConstDropZoneInfo * getDropZoneByAddressPath(const char * netaddress, const char *targetPath) const;
  129. virtual IConstDropZoneInfoIterator * getDropZoneIterator() const;
  130. unsigned getNumberOfMachines() const { buildMachineCache(); return numOfMachines; }
  131. IConstMachineInfo * getMachineByIndex(unsigned index) const;
  132. unsigned getNumberOfDropZones() const { buildDropZoneCache(); return numOfDropZones; }
  133. IConstDropZoneInfo * getDropZoneByIndex(unsigned index) const;
  134. bool isDropZoneRestrictionEnabled() const;
  135. };
  136. class CLockedEnvironment : implements IEnvironment, public CInterface
  137. {
  138. public:
  139. //note that order of construction/destruction is important
  140. Owned<CLocalEnvironment> c;
  141. Owned<CLocalEnvironment> env;
  142. Owned<CLocalEnvironment> constEnv;
  143. IMPLEMENT_IINTERFACE;
  144. CLockedEnvironment(CLocalEnvironment *_c)
  145. {
  146. Owned<IRemoteConnection> connection = _c->getConnection();
  147. if (connection)
  148. {
  149. constEnv.set(_c); //save original constant environment
  150. //we only wish to allow one party to allow updating the environment.
  151. //
  152. //create a new /NewEnvironment subtree, locked for read/write access for self and entire subtree; delete on disconnect
  153. //
  154. StringBuffer newName("/New");
  155. newName.append(constEnv->getPath());
  156. const unsigned int mode = RTM_CREATE | RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE |
  157. RTM_LOCK_SUB | RTM_DELETE_ON_DISCONNECT;
  158. Owned<IRemoteConnection> conn = querySDS().connect(newName.str(), myProcessSession(), mode, SDS_LOCK_TIMEOUT);
  159. if (conn == nullptr)
  160. {
  161. if (environmentTraceLevel > 0)
  162. PrintLog("Failed to create locked environment %s", newName.str());
  163. throw MakeStringException(-1, "Failed to get a lock on environment /%s", newName.str());
  164. }
  165. //save the locked environment
  166. env.setown(new CLocalEnvironment(conn, nullptr, newName.str()));
  167. //get a lock on the const environment
  168. const unsigned int mode2 = RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE | RTM_LOCK_SUB;
  169. Owned<IRemoteConnection> conn2 = querySDS().connect(constEnv->getPath(), myProcessSession(), mode2, SDS_LOCK_TIMEOUT);
  170. if (conn2 == nullptr)
  171. {
  172. if (environmentTraceLevel > 0)
  173. PrintLog("Failed to lock environment %s", constEnv->getPath());
  174. throw MakeStringException(-1, "Failed to get a lock on environment /%s", constEnv->getPath());
  175. }
  176. //copy const environment to our member environment
  177. Owned<IPropertyTree> pSrc = conn2->getRoot();
  178. c.setown( new CLocalEnvironment(nullptr, createPTreeFromIPT(pSrc)));
  179. conn2->rollback();
  180. }
  181. else
  182. {
  183. c.set(_c);
  184. }
  185. }
  186. virtual ~CLockedEnvironment()
  187. {
  188. }
  189. virtual IStringVal & getName(IStringVal & str) const
  190. { return c->getName(str); }
  191. virtual IStringVal & getXML(IStringVal & str) const
  192. { return c->getXML(str); }
  193. virtual IPropertyTree & getPTree() const
  194. { return c->getPTree(); }
  195. virtual IConstDomainInfo * getDomain(const char * name) const
  196. { return c->getDomain(name); }
  197. virtual IConstMachineInfo * getMachine(const char * name) const
  198. { return c->getMachine(name); }
  199. virtual IConstMachineInfo * getMachineByAddress(const char * machineIp) const
  200. { return c->getMachineByAddress(machineIp); }
  201. virtual IConstMachineInfo * getMachineForLocalHost() const
  202. { return c->getMachineForLocalHost(); }
  203. virtual IConstDropZoneInfo * getDropZone(const char * name) const
  204. { return c->getDropZone(name); }
  205. virtual IConstInstanceInfo * getInstance(const char *type, const char *version, const char *domain) const
  206. { return c->getInstance(type, version, domain); }
  207. virtual bool getRunInfo(IStringVal & path, IStringVal & dir, const char *type, const char *version, const char *machineaddr,const char *defprogname) const
  208. { return c->getRunInfo(path, dir, type, version, machineaddr, defprogname); }
  209. virtual IConstComputerTypeInfo * getComputerType(const char * name) const
  210. { return c->getComputerType(name); }
  211. virtual IEnvironment & lock() const
  212. { ((CInterface*)this)->Link(); return *(IEnvironment*)this; }
  213. virtual void commit();
  214. virtual void rollback();
  215. virtual void setXML(const char * pstr)
  216. { c->setXML(pstr); }
  217. virtual void preload()
  218. { c->preload(); }
  219. virtual bool isConstEnvironment() const { return false; }
  220. virtual void clearCache() { c->clearCache(); }
  221. virtual IConstMachineInfoIterator * getMachineIterator() const
  222. { return c->getMachineIterator(); }
  223. virtual IConstDropZoneInfoIterator * getDropZoneIteratorByAddress(const char * address) const
  224. { return c->getDropZoneIteratorByAddress(address); }
  225. virtual IConstDropZoneInfo * getDropZoneByAddressPath(const char * netaddress, const char *targetPath) const
  226. { return c->getDropZoneByAddressPath(netaddress, targetPath); }
  227. virtual IConstDropZoneInfoIterator * getDropZoneIterator() const
  228. { return c->getDropZoneIterator(); }
  229. virtual bool isDropZoneRestrictionEnabled() const
  230. { return c->isDropZoneRestrictionEnabled(); }
  231. };
  232. void CLockedEnvironment::commit()
  233. {
  234. if (constEnv)
  235. {
  236. //get a lock on const environment momentarily
  237. const unsigned int mode2 = RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE | RTM_LOCK_SUB;
  238. Owned<IRemoteConnection> conn2 = querySDS().connect(constEnv->getPath(), myProcessSession(), mode2, SDS_LOCK_TIMEOUT);
  239. if (conn2 == nullptr)
  240. {
  241. if (environmentTraceLevel > 0)
  242. PrintLog("Failed to lock environment %s", constEnv->getPath());
  243. throw MakeStringException(-1, "Failed to get a lock on environment /%s", constEnv->getPath());
  244. }
  245. //copy locked environment to const environment
  246. Owned<IPropertyTree> pSrc = &getPTree();
  247. Owned<IPropertyTree> pDst = conn2->queryRoot()->getBranch(nullptr);
  248. // JCS - I think it could (and would be more efficient if it had kept the original read lock connection to Env
  249. // - instead of using NewEnv as lock point, still work on copy, then changeMode of original connect
  250. // - as opposed to current scheme, where it recoonects in write mode and has to lazy fetch original env to update.
  251. // ensures pDst is equal to pSrc, whilst minimizing changes to pDst
  252. try { synchronizePTree(pDst, pSrc); }
  253. catch (IException *) { conn2->rollback(); throw; }
  254. conn2->commit();
  255. }
  256. else
  257. {
  258. Owned<IRemoteConnection> conn = c->getConnection();
  259. conn->commit();
  260. }
  261. }
  262. void CLockedEnvironment::rollback()
  263. {
  264. if (constEnv)
  265. {
  266. //get a lock on const environment momentarily
  267. const unsigned int mode2 = RTM_CREATE_QUERY | RTM_LOCK_READ | RTM_LOCK_WRITE | RTM_LOCK_SUB;
  268. Owned<IRemoteConnection> conn2 = querySDS().connect(constEnv->getPath(), myProcessSession(), mode2, SDS_LOCK_TIMEOUT);
  269. if (conn2 == nullptr)
  270. {
  271. if (environmentTraceLevel > 0)
  272. PrintLog("Failed to lock environment %s", constEnv->getPath());
  273. throw MakeStringException(-1, "Failed to get a lock on environment /%s", constEnv->getPath());
  274. }
  275. //copy const environment to locked environment (as it stands now) again losing any changes we made
  276. Owned<IPropertyTree> pSrc = conn2->getRoot();
  277. Owned<IPropertyTree> pDst = &getPTree();
  278. pDst->removeTree( pDst->queryPropTree("Hardware") );
  279. pDst->removeTree( pDst->queryPropTree("Software") );
  280. pDst->removeTree( pDst->queryPropTree("Programs") );
  281. pDst->removeTree( pDst->queryPropTree("Data") );
  282. mergePTree(pDst, pSrc);
  283. conn2->rollback();
  284. }
  285. else
  286. {
  287. Owned<IRemoteConnection> conn = c->getConnection();
  288. conn->rollback();
  289. }
  290. }
  291. //==========================================================================================
  292. // the following class implements notification handler for subscription to dali for environment
  293. // updates by other clients and is used by environment factory below. This also serves as
  294. // a sample self-contained implementation that can be easily tailored for other purposes.
  295. //==========================================================================================
  296. class CSdsSubscription : implements ISDSSubscription, public CInterface
  297. {
  298. public:
  299. CSdsSubscription(IEnvironmentFactory &_factory) : factory(_factory)
  300. {
  301. m_constEnvUpdated = false;
  302. sub_id = factory.subscribe(this);
  303. }
  304. virtual ~CSdsSubscription()
  305. {
  306. /* note that ideally, we would make this class automatically
  307. unsubscribe in this destructor. However, underlying dali client
  308. layer (CDaliSubscriptionManagerStub) links to this object and so
  309. object would not get destroyed just by an application releasing it.
  310. The application either needs to explicitly unsubscribe or close
  311. the environment which unsubscribes during close down. */
  312. }
  313. void unsubscribe()
  314. {
  315. synchronized block(m_mutexEnv);
  316. if (sub_id)
  317. {
  318. factory.unsubscribe(sub_id);
  319. sub_id = 0;
  320. }
  321. }
  322. IMPLEMENT_IINTERFACE;
  323. //another client (like configenv) may have updated the environment and we got notified
  324. //(thanks to our subscription) but don't just reload it yet since this notification is sent on
  325. //another thread asynchronously and we may be actively working with the old environment. Just
  326. //invoke handleEnvironmentChange() when we are ready to invalidate cache in environment factory.
  327. //
  328. void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen=0, const void *valueData=nullptr)
  329. {
  330. DBGLOG("Environment was updated by another client of Dali server. Invalidating cache.\n");
  331. synchronized block(m_mutexEnv);
  332. m_constEnvUpdated = true;
  333. }
  334. void handleEnvironmentChange()
  335. {
  336. synchronized block(m_mutexEnv);
  337. if (m_constEnvUpdated)
  338. {
  339. Owned<IConstEnvironment> constEnv = factory.openEnvironment();
  340. constEnv->clearCache();
  341. m_constEnvUpdated = false;
  342. }
  343. }
  344. private:
  345. SubscriptionId sub_id;
  346. Mutex m_mutexEnv;
  347. bool m_constEnvUpdated;
  348. IEnvironmentFactory &factory;
  349. };
  350. //==========================================================================================
  351. class CEnvironmentFactory : public CInterface,
  352. implements IEnvironmentFactory, implements IDaliClientShutdown
  353. {
  354. public:
  355. IMPLEMENT_IINTERFACE;
  356. typedef ArrayOf<SubscriptionId> SubscriptionIDs;
  357. SubscriptionIDs subIDs;
  358. Mutex mutex;
  359. Owned<CSdsSubscription> subscription;
  360. CEnvironmentFactory()
  361. {
  362. }
  363. virtual void clientShutdown();
  364. virtual ~CEnvironmentFactory()
  365. {
  366. close(); //just in case it was not explicitly closed
  367. }
  368. virtual IConstEnvironment* openEnvironment()
  369. {
  370. synchronized procedure(mutex);
  371. if (!cache)
  372. {
  373. Owned<IRemoteConnection> conn = querySDS().connect("/Environment", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
  374. if (conn)
  375. cache.setown(new CLocalEnvironment(conn));
  376. }
  377. if (!cache)
  378. throw MakeStringException(0, "Failed to get environment information");
  379. return cache.getLink();
  380. }
  381. virtual IEnvironment* updateEnvironment()
  382. {
  383. Owned<IConstEnvironment> pConstEnv = openEnvironment();
  384. synchronized procedure(mutex);
  385. return &pConstEnv->lock();
  386. }
  387. virtual IEnvironment * loadLocalEnvironmentFile(const char * filename)
  388. {
  389. Owned<IPropertyTree> ptree = createPTreeFromXMLFile(filename, ipt_lowmem);
  390. Owned<CLocalEnvironment> pLocalEnv = new CLocalEnvironment(nullptr, ptree);
  391. return new CLockedEnvironment(pLocalEnv);
  392. }
  393. virtual IEnvironment * loadLocalEnvironment(const char * xml)
  394. {
  395. Owned<IPropertyTree> ptree = createPTreeFromXMLString(xml, ipt_lowmem);
  396. Owned<CLocalEnvironment> pLocalEnv = new CLocalEnvironment(nullptr, ptree);
  397. return new CLockedEnvironment(pLocalEnv);
  398. }
  399. void close()
  400. {
  401. SubscriptionIDs copySubIDs;
  402. {
  403. synchronized procedure(mutex);
  404. cache.clear();
  405. //save the active subscriptions in another array
  406. //so they can be unsubscribed without causing deadlock
  407. // since ~CSdsSubscription() would ask us to unsubscribe the
  408. //same requiring a mutex lock (copy is a little price for this
  409. //normally small/empty array).
  410. //
  411. ForEachItemIn(i, subIDs)
  412. copySubIDs.append(subIDs.item(i));
  413. subIDs.kill();
  414. }
  415. //now unsubscribe all outstanding subscriptions
  416. //
  417. subscription.clear();
  418. ForEachItemIn(i, copySubIDs)
  419. querySDS().unsubscribe( copySubIDs.item(i) );
  420. }
  421. virtual SubscriptionId subscribe(ISDSSubscription* pSubHandler)
  422. {
  423. SubscriptionId sub_id = querySDS().subscribe("/Environment", *pSubHandler);
  424. synchronized procedure(mutex);
  425. subIDs.append(sub_id);
  426. return sub_id;
  427. }
  428. virtual void unsubscribe(SubscriptionId sub_id)
  429. {
  430. synchronized procedure(mutex);
  431. aindex_t i = subIDs.find(sub_id);
  432. if (i != NotFound)
  433. {
  434. querySDS().unsubscribe(sub_id);
  435. subIDs.remove(i);
  436. }
  437. }
  438. virtual void validateCache()
  439. {
  440. if (!subscription)
  441. subscription.setown( new CSdsSubscription(*this) );
  442. subscription->handleEnvironmentChange();
  443. }
  444. private:
  445. IRemoteConnection* connect(const char *xpath, unsigned flags)
  446. {
  447. return querySDS().connect(xpath, myProcessSession(), flags, SDS_LOCK_TIMEOUT);
  448. }
  449. };
  450. static CEnvironmentFactory *factory=nullptr;
  451. void CEnvironmentFactory::clientShutdown()
  452. {
  453. closeEnvironment();
  454. }
  455. MODULE_INIT(INIT_PRIORITY_ENV_ENVIRONMENT)
  456. {
  457. return true;
  458. }
  459. MODULE_EXIT()
  460. {
  461. ::Release(factory);
  462. }
  463. //==========================================================================================
  464. class CConstEnvBase : public CInterface
  465. {
  466. protected:
  467. const CLocalEnvironment* env; // Not linked - would be circular....
  468. // That could cause problems
  469. Linked<IPropertyTree> root;
  470. public:
  471. CConstEnvBase(const CLocalEnvironment* _env, IPropertyTree *_root)
  472. : env(_env), root(_root)
  473. {
  474. }
  475. IStringVal& getXML(IStringVal &str) const
  476. {
  477. StringBuffer x;
  478. toXML(root->queryBranch("."), x);
  479. str.set(x.str());
  480. return str;
  481. };
  482. IStringVal& getName(IStringVal &str) const
  483. {
  484. str.set(root->queryProp("@name"));
  485. return str;
  486. }
  487. IPropertyTree& getPTree() const
  488. {
  489. return *LINK(root);
  490. }
  491. };
  492. #define IMPLEMENT_ICONSTENVBASE \
  493. virtual IStringVal& getXML(IStringVal &str) const { return CConstEnvBase::getXML(str); } \
  494. virtual IStringVal& getName(IStringVal &str) const { return CConstEnvBase::getName(str); } \
  495. virtual IPropertyTree& getPTree() const { return CConstEnvBase::getPTree(); }
  496. //==========================================================================================
  497. class CConstDomainInfo : public CConstEnvBase, implements IConstDomainInfo
  498. {
  499. public:
  500. IMPLEMENT_IINTERFACE;
  501. IMPLEMENT_ICONSTENVBASE;
  502. CConstDomainInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root) {}
  503. virtual void getAccountInfo(IStringVal &name, IStringVal &pw) const
  504. {
  505. if (root->hasProp("@username"))
  506. name.set(root->queryProp("@username"));
  507. else
  508. name.clear();
  509. if (root->hasProp("@password"))
  510. {
  511. StringBuffer pwd;
  512. decrypt(pwd, root->queryProp("@password"));
  513. pw.set(pwd.str());
  514. }
  515. else
  516. pw.clear();
  517. }
  518. virtual void getSnmpSecurityString(IStringVal & securityString) const
  519. {
  520. if (root->hasProp("@snmpSecurityString"))
  521. {
  522. StringBuffer sec_string;
  523. decrypt(sec_string, root->queryProp("@snmpSecurityString"));
  524. securityString.set(sec_string.str());
  525. }
  526. else
  527. securityString.set("");
  528. }
  529. virtual void getSSHAccountInfo(IStringVal &name, IStringVal &sshKeyFile, IStringVal& sshKeyPassphrase) const
  530. {
  531. if (root->hasProp("@username"))
  532. name.set(root->queryProp("@username"));
  533. else
  534. name.clear();
  535. if (root->hasProp("@sshKeyFile"))
  536. sshKeyFile.set(root->queryProp("@sshKeyFile"));
  537. else
  538. sshKeyFile.clear();
  539. if (root->hasProp("@sshKeyPassphrase"))
  540. sshKeyPassphrase.set(root->queryProp("@sshKeyPassphrase"));
  541. else
  542. sshKeyPassphrase.clear();
  543. }
  544. };
  545. //==========================================================================================
  546. struct mapOsEnums { EnvMachineOS val; const char *str; };
  547. static EnvMachineOS getEnum(IPropertyTree *p, const char *propname, mapOsEnums *map)
  548. {
  549. const char *v = p->queryProp(propname);
  550. if (v && *v)
  551. {
  552. while (map->str)
  553. {
  554. if (stricmp(v, map->str)==0)
  555. return map->val;
  556. map++;
  557. }
  558. throw MakeStringException(0, "Unknown operating system: \"%s\"", v);
  559. }
  560. return MachineOsUnknown;
  561. }
  562. struct mapStateEnums { EnvMachineState val; const char *str; };
  563. static EnvMachineState getEnum(IPropertyTree *p, const char *propname, mapStateEnums *map)
  564. {
  565. const char *v = p->queryProp(propname);
  566. if (v && *v)
  567. {
  568. while (map->str)
  569. {
  570. if (stricmp(v, map->str)==0)
  571. return map->val;
  572. map++;
  573. }
  574. assertex(!"Unexpected value in getEnum");
  575. }
  576. return MachineStateUnknown;
  577. }
  578. mapOsEnums OperatingSystems[] = {
  579. { MachineOsW2K, "W2K" },
  580. { MachineOsSolaris, "solaris" },
  581. { MachineOsLinux, "linux" },
  582. { MachineOsSize, nullptr }
  583. };
  584. mapStateEnums MachineStates[] = {
  585. { MachineStateAvailable, "Available" },
  586. { MachineStateUnavailable, "Unavailable" },
  587. { MachineStateUnknown, "Unknown" }
  588. };
  589. //==========================================================================================
  590. class CConstMachineInfo : public CConstEnvBase, implements IConstMachineInfo
  591. {
  592. public:
  593. IMPLEMENT_IINTERFACE;
  594. IMPLEMENT_ICONSTENVBASE;
  595. CConstMachineInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root) {}
  596. virtual IConstDomainInfo* getDomain() const
  597. {
  598. return env->getDomain(root->queryProp("@domain"));
  599. }
  600. virtual IStringVal& getNetAddress(IStringVal &str) const
  601. {
  602. str.set(root->queryProp("@netAddress"));
  603. return str;
  604. }
  605. virtual IStringVal& getDescription(IStringVal &str) const
  606. {
  607. UNIMPLEMENTED;
  608. }
  609. virtual unsigned getNicSpeedMbitSec() const
  610. {
  611. const char * v = root->queryProp("@nicSpeed");
  612. if (v && *v)
  613. return atoi(v);
  614. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  615. if (type)
  616. return type->getNicSpeedMbitSec();
  617. return 0;
  618. }
  619. virtual EnvMachineOS getOS() const
  620. {
  621. EnvMachineOS os = getEnum(root, "@opSys", OperatingSystems);
  622. if (os != MachineOsUnknown)
  623. return os;
  624. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  625. if (type)
  626. return type->getOS();
  627. return MachineOsUnknown;
  628. }
  629. virtual EnvMachineState getState() const
  630. {
  631. return getEnum(root, "@state", MachineStates);
  632. }
  633. };
  634. //==========================================================================================
  635. class CConstComputerTypeInfo : public CConstEnvBase, implements IConstComputerTypeInfo
  636. {
  637. public:
  638. IMPLEMENT_IINTERFACE;
  639. IMPLEMENT_ICONSTENVBASE;
  640. CConstComputerTypeInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root) {}
  641. virtual EnvMachineOS getOS() const
  642. {
  643. EnvMachineOS os = getEnum(root, "@opSys", OperatingSystems);
  644. if (os != MachineOsUnknown)
  645. return os;
  646. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  647. if (type && (type.get() != this))
  648. return type->getOS();
  649. return MachineOsUnknown;
  650. }
  651. virtual unsigned getNicSpeedMbitSec() const
  652. {
  653. const char * v = root->queryProp("@nicSpeed");
  654. if (v && *v)
  655. return atoi(v);
  656. Owned<IConstComputerTypeInfo> type = env->getComputerType(root->queryProp("@computerType"));
  657. if (type && (type.get() != this))
  658. return type->getNicSpeedMbitSec();
  659. return 0;
  660. }
  661. };
  662. //==========================================================================================
  663. class CConstInstanceInfo : public CConstEnvBase, implements IConstInstanceInfo
  664. {
  665. public:
  666. IMPLEMENT_IINTERFACE;
  667. IMPLEMENT_ICONSTENVBASE;
  668. CConstInstanceInfo(const CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root)
  669. {
  670. }
  671. virtual IConstMachineInfo * getMachine() const
  672. {
  673. return env->getMachine(root->queryProp("@computer"));
  674. }
  675. virtual IStringVal & getEndPoint(IStringVal & str) const
  676. {
  677. SCMStringBuffer ep;
  678. Owned<IConstMachineInfo> machine = getMachine();
  679. if (machine)
  680. {
  681. machine->getNetAddress(ep);
  682. const char *port = root->queryProp("@port");
  683. if (port)
  684. ep.s.append(':').append(port);
  685. }
  686. str.set(ep.str());
  687. return str;
  688. }
  689. virtual IStringVal & getExecutableDirectory(IStringVal & str) const
  690. {
  691. // this is the deploy directory so uses local path separators (I suspect this call is LEGACY now)
  692. SCMStringBuffer ep;
  693. Owned<IConstMachineInfo> machine = getMachine();
  694. if (machine)
  695. {
  696. machine->getNetAddress(ep);
  697. ep.s.insert(0, PATHSEPSTR PATHSEPSTR);
  698. }
  699. ep.s.append(PATHSEPCHAR).append(root->queryProp("@directory"));
  700. str.set(ep.str());
  701. return str;
  702. }
  703. virtual bool doGetRunInfo(IStringVal & progpath, IStringVal & workdir, const char *defprogname, bool useprog) const
  704. {
  705. // this is remote path i.e. path should match *target* nodes format
  706. Owned<IConstMachineInfo> machine = getMachine();
  707. if (!machine)
  708. return false;
  709. char psep;
  710. bool appendexe;
  711. switch (machine->getOS())
  712. {
  713. case MachineOsSolaris:
  714. case MachineOsLinux:
  715. psep = '/';
  716. appendexe = false;
  717. break;
  718. default:
  719. psep = '\\';
  720. appendexe = true;
  721. }
  722. StringBuffer tmp;
  723. const char *program = useprog?root->queryProp("@program"):nullptr; // if program specified assume absolute
  724. if (!program||!*program)
  725. {
  726. SCMStringBuffer ep;
  727. machine->getNetAddress(ep);
  728. const char *dir = root->queryProp("@directory");
  729. if (dir)
  730. {
  731. if (isPathSepChar(*dir))
  732. dir++;
  733. if (!*dir)
  734. return false;
  735. tmp.append(psep).append(psep).append(ep.s).append(psep);
  736. do {
  737. if (isPathSepChar(*dir))
  738. tmp.append(psep);
  739. else
  740. tmp.append(*dir);
  741. dir++;
  742. } while (*dir);
  743. if (!isPathSepChar(tmp.charAt(tmp.length()-1)))
  744. tmp.append(psep);
  745. tmp.append(defprogname);
  746. size32_t l = strlen(defprogname);
  747. if (appendexe&&((l<5)||(stricmp(defprogname+l-4,".exe")!=0)))
  748. tmp.append(".exe");
  749. }
  750. program = tmp.str();
  751. }
  752. progpath.set(program);
  753. const char *workd = root->queryProp("@workdir"); // if program specified assume absolute
  754. workdir.set(workd?workd:"");
  755. return true;
  756. }
  757. virtual bool getRunInfo(IStringVal & progpath, IStringVal & workdir, const char *defprogname) const
  758. {
  759. return doGetRunInfo(progpath,workdir,defprogname,true);
  760. }
  761. virtual unsigned getPort() const
  762. {
  763. return root->getPropInt("@port", 0);
  764. }
  765. };
  766. class CConstDropZoneServerInfo : public CConstEnvBase, implements IConstDropZoneServerInfo
  767. {
  768. public:
  769. IMPLEMENT_IINTERFACE;
  770. IMPLEMENT_ICONSTENVBASE;
  771. CConstDropZoneServerInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root), prop(root) {}
  772. virtual StringBuffer & getName(StringBuffer & name) const
  773. {
  774. name.append(prop->queryProp("@name"));
  775. return name;
  776. }
  777. virtual StringBuffer & getServer(StringBuffer & server) const
  778. {
  779. server.append(prop->queryProp("@server"));
  780. return server;
  781. }
  782. private:
  783. IPropertyTree * prop;
  784. };
  785. class CConstDropZoneInfo : public CConstEnvBase, implements IConstDropZoneInfo
  786. {
  787. public:
  788. IMPLEMENT_IINTERFACE;
  789. IMPLEMENT_ICONSTENVBASE;
  790. CConstDropZoneInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root)
  791. {
  792. getStandardPosixPath(posixPath, root->queryProp("@directory"));
  793. }
  794. virtual IStringVal& getComputerName(IStringVal &str) const
  795. {
  796. str.set(root->queryProp("@computer"));
  797. return str;
  798. }
  799. virtual IStringVal& getDescription(IStringVal &str) const
  800. {
  801. str.set(root->queryProp("@description"));
  802. return str;
  803. }
  804. virtual IStringVal& getDirectory(IStringVal &str) const
  805. {
  806. str.set(posixPath.str());
  807. return str;
  808. }
  809. virtual IStringVal& getUMask(IStringVal &str) const
  810. {
  811. if (root->hasProp("@umask"))
  812. str.set(root->queryProp("@umask"));
  813. return str;
  814. }
  815. virtual bool isECLWatchVisible() const
  816. {
  817. return root->getPropBool("@ECLWatchVisible", true);
  818. }
  819. virtual IConstDropZoneServerInfoIterator * getServers() const
  820. {
  821. return new CConstDropZoneServerInfoIterator(this);
  822. }
  823. private:
  824. StringBuffer posixPath;
  825. };
  826. #if 0
  827. //==========================================================================================
  828. class CConstProcessInfo : public CConstEnvBase, implements IConstProcessInfo
  829. {
  830. IArrayOf<IConstInstanceInfo> w;
  831. CArrayIteratorOf<IInterface, IIterator> it;
  832. public:
  833. IMPLEMENT_IINTERFACE;
  834. IMPLEMENT_ICONSTENVBASE;
  835. CConstProcessInfo(CLocalEnvironment *env, IPropertyTree *root) : CConstEnvBase(env, root), it(w)
  836. {
  837. Owned<IPropertyTreeIterator> _it = root->getElements("*"); // MORE - should be instance
  838. for (_it->first(); _it->isValid(); _it->next())
  839. {
  840. IPropertyTree *rp = &_it->query();
  841. w.append(*new CConstInstanceInfo(env, rp)); // CConstInstanceInfo will link rp
  842. }
  843. }
  844. bool first() { return it.first(); }
  845. bool isValid() { return it.isValid(); }
  846. bool next() { return it.next(); }
  847. IConstInstanceInfo & query() { return (IConstInstanceInfo &) it.query();}
  848. virtual IConstInstanceInfo * getInstance(const char *domain)
  849. {
  850. for (int pass=0; pass<2; pass++)
  851. {
  852. ForEachItemIn(idx, w)
  853. {
  854. Owned<IConstMachineInfo> m = w.item(idx).getMachine();
  855. if (m)
  856. {
  857. Owned<IConstDomainInfo> dm = m->getDomain();
  858. if (dm)
  859. {
  860. StringBuffer thisdomain;
  861. //dm->getName(StringBufferAdaptor(thisdomain)); // confuses g++
  862. StringBufferAdaptor strval(thisdomain);
  863. dm->getName(strval);
  864. if (thisdomain.length() && strcmp(domain, thisdomain.str())==0)
  865. return LINK(&w.item(idx));
  866. }
  867. }
  868. }
  869. }
  870. return nullptr;
  871. }
  872. };
  873. #endif
  874. //==========================================================================================
  875. CLocalEnvironment::CLocalEnvironment(const char* environmentFile)
  876. {
  877. if (environmentFile && *environmentFile)
  878. {
  879. IPropertyTree* root = createPTreeFromXMLFile(environmentFile);
  880. if (root)
  881. p.set(root);
  882. }
  883. init();
  884. }
  885. CLocalEnvironment::CLocalEnvironment(IRemoteConnection *_conn, IPropertyTree* root/*=nullptr*/,
  886. const char* path/*="/Environment"*/)
  887. : xPath(path)
  888. {
  889. conn.set(_conn);
  890. if (root)
  891. p.set(root);
  892. else
  893. p.setown(conn->getRoot());
  894. init();
  895. }
  896. void CLocalEnvironment::init()
  897. {
  898. machineCacheBuilt = false;
  899. dropZoneCacheBuilt = false;
  900. numOfMachines = 0;
  901. numOfDropZones = 0;
  902. isDropZoneRestrictionLoaded = false;
  903. }
  904. CLocalEnvironment::~CLocalEnvironment()
  905. {
  906. if (conn)
  907. conn->rollback();
  908. }
  909. IEnvironment& CLocalEnvironment::lock() const
  910. {
  911. return *new CLockedEnvironment((CLocalEnvironment*)this);
  912. }
  913. IStringVal & CLocalEnvironment::getName(IStringVal & str) const
  914. {
  915. synchronized procedure(safeCache);
  916. str.set(p->queryProp("@name"));
  917. return str;
  918. }
  919. IStringVal & CLocalEnvironment::getXML(IStringVal & str) const
  920. {
  921. StringBuffer xml;
  922. {
  923. synchronized procedure(safeCache);
  924. toXML(p->queryBranch("."), xml);
  925. }
  926. str.set(xml.str());
  927. return str;
  928. }
  929. IPropertyTree & CLocalEnvironment::getPTree() const
  930. {
  931. synchronized procedure(safeCache);
  932. return *LINK(p);
  933. }
  934. IConstEnvBase * CLocalEnvironment::getCache(const char *path) const
  935. {
  936. IConstEnvBase * ret = cache.getValue(path);
  937. ::Link(ret);
  938. return ret;
  939. }
  940. void CLocalEnvironment::setCache(const char *path, IConstEnvBase *value) const
  941. {
  942. cache.setValue(path, value);
  943. }
  944. IConstDomainInfo * CLocalEnvironment::getDomain(const char * name) const
  945. {
  946. if (!name)
  947. return nullptr;
  948. StringBuffer xpath;
  949. xpath.appendf("Hardware/Domain[@name=\"%s\"]", name);
  950. synchronized procedure(safeCache);
  951. IConstEnvBase *cached = getCache(xpath.str());
  952. if (!cached)
  953. {
  954. IPropertyTree *d = p->queryPropTree(xpath.str());
  955. if (!d)
  956. return nullptr;
  957. cached = new CConstDomainInfo((CLocalEnvironment *) this, d);
  958. setCache(xpath.str(), cached);
  959. }
  960. return (IConstDomainInfo *) cached;
  961. }
  962. void CLocalEnvironment::buildMachineCache() const
  963. {
  964. synchronized procedure(safeCache);
  965. if (!machineCacheBuilt)
  966. {
  967. Owned<IPropertyTreeIterator> it = p->getElements("Hardware/Computer");
  968. ForEach(*it)
  969. {
  970. const char *name = it->query().queryProp("@name");
  971. if (name)
  972. {
  973. StringBuffer x("Hardware/Computer[@name=\"");
  974. x.append(name).append("\"]");
  975. Owned<IConstEnvBase> cached = new CConstMachineInfo((CLocalEnvironment *) this, &it->query());
  976. cache.setValue(x.str(), cached);
  977. }
  978. const char * netAddress = it->query().queryProp("@netAddress");
  979. if (netAddress)
  980. {
  981. StringBuffer x("Hardware/Computer[@netAddress=\"");
  982. x.append(netAddress).append("\"]");
  983. Owned<IConstEnvBase> cached = new CConstMachineInfo((CLocalEnvironment *) this, &it->query());
  984. cache.setValue(x.str(), cached);
  985. IpAddress ip;
  986. ip.ipset(netAddress);
  987. if (ip.isLocal())
  988. cache.setValue("Hardware/Computer[@netAddress=\".\"]", cached);
  989. }
  990. numOfMachines++;
  991. StringBuffer x("Hardware/Computer[@id=\"");
  992. x.append(MACHINE_PREFIX).append(numOfMachines).append("\"]");
  993. Owned<IConstEnvBase> cached = new CConstMachineInfo((CLocalEnvironment *) this, &it->query());
  994. cache.setValue(x.str(), cached);
  995. }
  996. machineCacheBuilt = true;
  997. }
  998. }
  999. void CLocalEnvironment::buildDropZoneCache() const
  1000. {
  1001. synchronized procedure(safeCache);
  1002. if (!dropZoneCacheBuilt)
  1003. {
  1004. Owned<IPropertyTreeIterator> it = p->getElements("Software/DropZone");
  1005. ForEach(*it)
  1006. {
  1007. const char *name = it->query().queryProp("@name");
  1008. if (name)
  1009. {
  1010. StringBuffer x("Software/DropZone[@name=\"");
  1011. x.append(name).append("\"]");
  1012. Owned<IConstEnvBase> cached = new CConstDropZoneInfo((CLocalEnvironment *) this, &it->query());
  1013. cache.setValue(x.str(), cached);
  1014. }
  1015. numOfDropZones++;
  1016. StringBuffer x("Software/DropZone[@id=\"");
  1017. x.append(DROPZONE_SUFFIX).append(numOfDropZones).append("\"]");
  1018. Owned<IConstEnvBase> cached = new CConstDropZoneInfo((CLocalEnvironment *) this, &it->query());
  1019. cache.setValue(x.str(), cached);
  1020. }
  1021. dropZoneCacheBuilt = true;
  1022. }
  1023. }
  1024. IConstComputerTypeInfo * CLocalEnvironment::getComputerType(const char * name) const
  1025. {
  1026. if (!name)
  1027. return nullptr;
  1028. StringBuffer xpath;
  1029. xpath.appendf("Hardware/ComputerType[@name=\"%s\"]", name);
  1030. synchronized procedure(safeCache);
  1031. IConstEnvBase *cached = getCache(xpath.str());
  1032. if (!cached)
  1033. {
  1034. IPropertyTree *d = p->queryPropTree(xpath.str());
  1035. if (!d)
  1036. return nullptr;
  1037. cached = new CConstComputerTypeInfo((CLocalEnvironment *) this, d);
  1038. setCache(xpath.str(), cached);
  1039. }
  1040. return (CConstComputerTypeInfo *) cached;
  1041. }
  1042. IConstMachineInfo * CLocalEnvironment::getMachine(const char * name) const
  1043. {
  1044. if (!name)
  1045. return nullptr;
  1046. buildMachineCache();
  1047. StringBuffer xpath;
  1048. xpath.appendf("Hardware/Computer[@name=\"%s\"]", name);
  1049. synchronized procedure(safeCache);
  1050. IConstEnvBase *cached = getCache(xpath.str());
  1051. if (!cached)
  1052. {
  1053. IPropertyTree *d = p->queryPropTree(xpath.str());
  1054. if (!d)
  1055. return nullptr;
  1056. cached = new CConstMachineInfo((CLocalEnvironment *) this, d);
  1057. setCache(xpath.str(), cached);
  1058. }
  1059. return (CConstMachineInfo *) cached;
  1060. }
  1061. IConstMachineInfo * CLocalEnvironment::getMachineByAddress(const char * machineIp) const
  1062. {
  1063. if (!machineIp)
  1064. return nullptr;
  1065. buildMachineCache();
  1066. Owned<IPropertyTreeIterator> iter;
  1067. StringBuffer xpath;
  1068. xpath.appendf("Hardware/Computer[@netAddress=\"%s\"]", machineIp);
  1069. synchronized procedure(safeCache);
  1070. IConstEnvBase *cached = getCache(xpath.str());
  1071. if (!cached)
  1072. {
  1073. IPropertyTree *d = p->queryPropTree(xpath.str());
  1074. if (!d)
  1075. {
  1076. // I suspect not in the original spirit of this but look for resolved IP
  1077. Owned<IPropertyTreeIterator> iter = p->getElements("Hardware/Computer");
  1078. IpAddress ip;
  1079. ip.ipset(machineIp);
  1080. ForEach(*iter)
  1081. {
  1082. IPropertyTree &computer = iter->query();
  1083. IpAddress ip2;
  1084. const char *ips = computer.queryProp("@netAddress");
  1085. if (ips&&*ips)
  1086. {
  1087. ip2.ipset(ips);
  1088. if (ip.ipequals(ip2))
  1089. {
  1090. d = &computer;
  1091. break;
  1092. }
  1093. }
  1094. }
  1095. }
  1096. if (!d)
  1097. return nullptr;
  1098. StringBuffer xpath1;
  1099. xpath1.appendf("Hardware/Computer[@name=\"%s\"]", d->queryProp("@name"));
  1100. cached = getCache(xpath1.str());
  1101. if (!cached)
  1102. {
  1103. cached = new CConstMachineInfo((CLocalEnvironment *) this, d);
  1104. setCache(xpath1.str(), cached);
  1105. setCache(xpath.str(), cached);
  1106. }
  1107. }
  1108. return (CConstMachineInfo *) cached;
  1109. }
  1110. IConstMachineInfo * CLocalEnvironment::getMachineByIndex(unsigned index) const
  1111. {
  1112. if (!numOfMachines || (index == 0))
  1113. return nullptr;
  1114. buildMachineCache();
  1115. if (index > numOfMachines)
  1116. return nullptr;
  1117. StringBuffer xpath("Hardware/Computer[@id=\"");
  1118. xpath.append(MACHINE_PREFIX).append(index).append("\"]");
  1119. synchronized procedure(safeCache);
  1120. return (IConstMachineInfo *) getCache(xpath.str());
  1121. }
  1122. IConstMachineInfo * CLocalEnvironment::getMachineForLocalHost() const
  1123. {
  1124. buildMachineCache();
  1125. synchronized procedure(safeCache);
  1126. return (CConstMachineInfo *) getCache("Hardware/Computer[@netAddress=\".\"]");
  1127. }
  1128. IConstDropZoneInfo * CLocalEnvironment::getDropZone(const char * name) const
  1129. {
  1130. if (!name)
  1131. return nullptr;
  1132. buildDropZoneCache();
  1133. VStringBuffer xpath("Software/DropZone[@name=\"%s\"]", name);
  1134. synchronized procedure(safeCache);
  1135. return (CConstDropZoneInfo *) getCache(xpath.str());
  1136. }
  1137. IConstDropZoneInfo * CLocalEnvironment::getDropZoneByIndex(unsigned index) const
  1138. {
  1139. if (!numOfDropZones || (index == 0))
  1140. return nullptr;
  1141. buildDropZoneCache();
  1142. if (index > numOfDropZones)
  1143. return nullptr;
  1144. StringBuffer xpath("Software/DropZone[@id=\"");
  1145. xpath.append(DROPZONE_SUFFIX).append(index).append("\"]");
  1146. synchronized procedure(safeCache);
  1147. return (CConstDropZoneInfo *) getCache(xpath.str());
  1148. }
  1149. IConstInstanceInfo * CLocalEnvironment::getInstance(const char *type, const char *version, const char *domain) const
  1150. {
  1151. StringBuffer xpath("Software/");
  1152. xpath.append(type);
  1153. if (version)
  1154. xpath.append("[@version='").append(version).append("']");
  1155. xpath.append("/Instance");
  1156. synchronized procedure(safeCache);
  1157. Owned<IPropertyTreeIterator> _it = p->getElements(xpath);
  1158. for (_it->first(); _it->isValid(); _it->next())
  1159. {
  1160. IPropertyTree *rp = &_it->query();
  1161. Owned<CConstInstanceInfo> inst = new CConstInstanceInfo(this, rp); // CConstInstanceInfo will link rp
  1162. Owned<IConstMachineInfo> m = inst->getMachine();
  1163. if (m)
  1164. {
  1165. Owned<IConstDomainInfo> dm = m->getDomain();
  1166. if (dm)
  1167. {
  1168. SCMStringBuffer thisdomain;
  1169. dm->getName(thisdomain);
  1170. if (thisdomain.length() && strcmp(domain, thisdomain.str())==0)
  1171. return inst.getClear();
  1172. }
  1173. }
  1174. }
  1175. return nullptr;
  1176. }
  1177. CConstInstanceInfo * CLocalEnvironment::getInstanceByIP(const char *type, const char *version, IpAddress &ip) const
  1178. {
  1179. StringBuffer xpath("Software/");
  1180. xpath.append(type);
  1181. if (version)
  1182. xpath.append("[@version='").append(version).append("']");
  1183. xpath.append("/Instance");
  1184. synchronized procedure(safeCache);
  1185. assertex(p);
  1186. Owned<IPropertyTreeIterator> _it = p->getElements(xpath);
  1187. assertex(_it);
  1188. for (_it->first(); _it->isValid(); _it->next())
  1189. {
  1190. IPropertyTree *rp = &_it->query();
  1191. assertex(rp);
  1192. Owned<CConstInstanceInfo> inst = new CConstInstanceInfo(this, rp); // CConstInstanceInfo will link rp
  1193. Owned<IConstMachineInfo> m = inst->getMachine();
  1194. if (m)
  1195. {
  1196. SCMStringBuffer eps;
  1197. m->getNetAddress(eps);
  1198. SocketEndpoint ep(eps.str());
  1199. if (ep.ipequals(ip))
  1200. return inst.getClear();
  1201. }
  1202. }
  1203. return nullptr;
  1204. }
  1205. void CLocalEnvironment::unlockRemote()
  1206. {
  1207. #if 0
  1208. conn->commit(true);
  1209. conn->changeMode(0, SDS_LOCK_TIMEOUT);
  1210. #else
  1211. if (conn)
  1212. {
  1213. synchronized procedure(safeCache);
  1214. p.clear();
  1215. conn.setown(querySDS().connect(xPath.str(), myProcessSession(), 0, SDS_LOCK_TIMEOUT));
  1216. p.setown(conn->getRoot());
  1217. }
  1218. #endif
  1219. }
  1220. void CLocalEnvironment::preload()
  1221. {
  1222. synchronized procedure(safeCache);
  1223. p->queryBranch(".");
  1224. }
  1225. void CLocalEnvironment::setXML(const char *xml)
  1226. {
  1227. Owned<IPropertyTree> newRoot = createPTreeFromXMLString(xml, ipt_lowmem);
  1228. synchronized procedure(safeCache);
  1229. Owned<IPropertyTreeIterator> it = p->getElements("*");
  1230. ForEach(*it)
  1231. {
  1232. p->removeTree(&it->query());
  1233. }
  1234. it.setown(newRoot->getElements("*"));
  1235. ForEach(*it)
  1236. {
  1237. IPropertyTree *sub = &it->get();
  1238. p->addPropTree(sub->queryName(), sub);
  1239. }
  1240. }
  1241. bool CLocalEnvironment::getRunInfo(IStringVal & path, IStringVal & dir, const char * tag, const char * version, const char *machineaddr, const char *defprogname) const
  1242. {
  1243. try
  1244. {
  1245. // PrintLog("getExecutablePath %s %s %s", tag, version, machineaddr);
  1246. // first see if local machine with deployed on
  1247. SocketEndpoint ep(machineaddr);
  1248. Owned<CConstInstanceInfo> ipinstance = getInstanceByIP(tag, version, ep);
  1249. if (ipinstance)
  1250. {
  1251. StringAttr testpath;
  1252. StringAttrAdaptor teststrval(testpath);
  1253. if (ipinstance->doGetRunInfo(teststrval,dir,defprogname,false))
  1254. { // this returns full string
  1255. RemoteFilename rfn;
  1256. rfn.setRemotePath(testpath.get());
  1257. Owned<IFile> file = createIFile(rfn);
  1258. if (file->exists())
  1259. {
  1260. StringBuffer tmp;
  1261. rfn.getLocalPath(tmp);
  1262. path.set(tmp.str());
  1263. return true;
  1264. }
  1265. }
  1266. }
  1267. Owned<IConstMachineInfo> machine = getMachineByAddress(machineaddr);
  1268. if (!machine)
  1269. {
  1270. LOG(MCdebugInfo, unknownJob, "Unable to find machine for %s", machineaddr);
  1271. return false;
  1272. }
  1273. StringAttr targetdomain;
  1274. Owned<IConstDomainInfo> domain = machine->getDomain();
  1275. if (!domain)
  1276. {
  1277. LOG(MCdebugInfo, unknownJob, "Unable to find domain for %s", machineaddr);
  1278. return false;
  1279. }
  1280. //domain->getName(StringAttrAdaptor(targetdomain)); // confuses g++
  1281. StringAttrAdaptor strval(targetdomain);
  1282. domain->getName(strval);
  1283. Owned<IConstInstanceInfo> instance = getInstance(tag, version, targetdomain);
  1284. if (!instance)
  1285. {
  1286. LOG(MCdebugInfo, unknownJob, "Unable to find process %s for domain %s", tag, targetdomain.get());
  1287. return false;
  1288. }
  1289. return instance->getRunInfo(path,dir,defprogname);
  1290. }
  1291. catch (IException * e)
  1292. {
  1293. EXCLOG(e, "Extracting slave version");
  1294. e->Release();
  1295. return false;
  1296. }
  1297. }
  1298. void CLocalEnvironment::clearCache()
  1299. {
  1300. synchronized procedure(safeCache);
  1301. if (conn)
  1302. {
  1303. p.clear();
  1304. unsigned mode = 0;
  1305. try
  1306. {
  1307. conn->reload();
  1308. }
  1309. catch (IException *e)
  1310. {
  1311. EXCLOG(e, "Failed to reload connection");
  1312. e->Release();
  1313. mode = conn->queryMode();
  1314. conn.clear();
  1315. }
  1316. if (!conn)
  1317. conn.setown(querySDS().connect(xPath, myProcessSession(), mode, SDS_LOCK_TIMEOUT));
  1318. p.setown(conn->getRoot());
  1319. }
  1320. cache.kill();
  1321. init();
  1322. resetPasswordsFromSDS();
  1323. }
  1324. IConstDropZoneInfo * CLocalEnvironment::getDropZoneByAddressPath(const char * netaddress, const char *targetFilePath) const
  1325. {
  1326. IConstDropZoneInfo * dropZone = nullptr;
  1327. IpAddress targetIp(netaddress);
  1328. unsigned dropzonePathLen = _MAX_PATH + 1;
  1329. #ifdef _DEBUG
  1330. LOG(MCdebugInfo, unknownJob, "Netaddress: '%s', targetFilePath: '%s'", netaddress, targetFilePath);
  1331. #endif
  1332. // Check the directory path first
  1333. Owned<IConstDropZoneInfoIterator> zoneIt = getDropZoneIterator();
  1334. ForEach(*zoneIt)
  1335. {
  1336. SCMStringBuffer dropZoneDir;
  1337. zoneIt->query().getDirectory(dropZoneDir);
  1338. StringBuffer fullDropZoneDir(dropZoneDir.str());
  1339. addPathSepChar(fullDropZoneDir);
  1340. IConstDropZoneInfo * candidateDropZone = nullptr;
  1341. if (strncmp(fullDropZoneDir, targetFilePath, fullDropZoneDir.length()) == 0)
  1342. {
  1343. candidateDropZone = &zoneIt->query();
  1344. // The backward compatibility built in IConstDropZoneServerInfoIterator
  1345. Owned<IConstDropZoneServerInfoIterator> dropzoneServerListIt = candidateDropZone->getServers();
  1346. ForEach(*dropzoneServerListIt)
  1347. {
  1348. StringBuffer dropzoneServer;
  1349. dropzoneServerListIt->query().getServer(dropzoneServer);
  1350. // It can be a hostname or an IP -> get the IP
  1351. IpAddress serverIP(dropzoneServer.str());
  1352. #ifdef _DEBUG
  1353. StringBuffer serverIpString;
  1354. serverIP.getIpText(serverIpString);
  1355. LOG(MCdebugInfo, unknownJob, "Listed server: '%s', IP: '%s'", dropzoneServer.str(), serverIpString.str());
  1356. #endif
  1357. if (targetIp.ipequals(serverIP))
  1358. {
  1359. // OK the target is a valid machine in the server list we have a right drop zone candidate
  1360. // Keep this candidate drop zone if its directory path is shorter than we already have
  1361. if (dropzonePathLen > fullDropZoneDir.length())
  1362. {
  1363. dropzonePathLen = fullDropZoneDir.length();
  1364. dropZone = candidateDropZone;
  1365. }
  1366. break;
  1367. }
  1368. }
  1369. }
  1370. }
  1371. return LINK(dropZone);
  1372. }
  1373. IConstDropZoneInfoIterator * CLocalEnvironment::getDropZoneIteratorByAddress(const char *addr) const
  1374. {
  1375. class CByAddrIter : public CSimpleInterfaceOf<IConstDropZoneInfoIterator>
  1376. {
  1377. IArrayOf<IConstDropZoneInfo> matches;
  1378. unsigned cur = NotFound;
  1379. public:
  1380. CByAddrIter(IConstDropZoneInfoIterator *baseIter, const char *addr)
  1381. {
  1382. IpAddress toMatch(addr);
  1383. ForEach(*baseIter)
  1384. {
  1385. IConstDropZoneInfo &dz = baseIter->query();
  1386. Owned<IConstDropZoneServerInfoIterator> serverIter = dz.getServers();
  1387. ForEach(*serverIter)
  1388. {
  1389. IConstDropZoneServerInfo &serverElem = serverIter->query();
  1390. StringBuffer serverName;
  1391. IpAddress serverIp(serverElem.getServer(serverName).str());
  1392. if (serverIp.ipequals(toMatch))
  1393. {
  1394. matches.append(*LINK(&dz));
  1395. break;
  1396. }
  1397. }
  1398. }
  1399. }
  1400. virtual bool first() override
  1401. {
  1402. if (0 == matches.ordinality())
  1403. {
  1404. cur = NotFound;
  1405. return false;
  1406. }
  1407. cur = 0;
  1408. return true;
  1409. }
  1410. virtual bool next() override
  1411. {
  1412. if (cur+1==matches.ordinality())
  1413. {
  1414. cur = NotFound;
  1415. return false;
  1416. }
  1417. ++cur;
  1418. return true;
  1419. }
  1420. virtual bool isValid() override
  1421. {
  1422. return NotFound != cur;
  1423. }
  1424. virtual IConstDropZoneInfo &query() override
  1425. {
  1426. assertex(NotFound != cur);
  1427. return matches.item(cur);
  1428. }
  1429. virtual unsigned count() const override
  1430. {
  1431. return matches.ordinality();
  1432. }
  1433. };
  1434. Owned<IConstDropZoneInfoIterator> baseIter = new CConstDropZoneInfoIterator();
  1435. return new CByAddrIter(baseIter, addr);
  1436. }
  1437. IConstDropZoneInfoIterator * CLocalEnvironment::getDropZoneIterator() const
  1438. {
  1439. return new CConstDropZoneInfoIterator();
  1440. }
  1441. IConstMachineInfoIterator * CLocalEnvironment::getMachineIterator() const
  1442. {
  1443. return new CConstMachineInfoIterator();
  1444. }
  1445. bool CLocalEnvironment::isDropZoneRestrictionEnabled() const
  1446. {
  1447. if (!isDropZoneRestrictionLoaded)
  1448. {
  1449. dropZoneRestrictionEnabled = queryEnvironmentConf().getPropBool("useDropZoneRestriction", true);
  1450. isDropZoneRestrictionLoaded=true;
  1451. }
  1452. return dropZoneRestrictionEnabled;
  1453. }
  1454. //==========================================================================================
  1455. // Iterators implementation
  1456. CConstMachineInfoIterator::CConstMachineInfoIterator()
  1457. {
  1458. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  1459. constEnv.setown((CLocalEnvironment *)factory->openEnvironment());
  1460. maxIndex = constEnv->getNumberOfMachines();
  1461. }
  1462. bool CConstMachineInfoIterator::first()
  1463. {
  1464. index = 1;
  1465. curr.setown(constEnv->getMachineByIndex(index));
  1466. return curr != nullptr;
  1467. }
  1468. bool CConstMachineInfoIterator::next()
  1469. {
  1470. if (index < maxIndex)
  1471. {
  1472. index++;
  1473. curr.setown(constEnv->getMachineByIndex(index));
  1474. }
  1475. else
  1476. curr.clear();
  1477. return curr != nullptr;
  1478. }
  1479. bool CConstMachineInfoIterator::isValid()
  1480. {
  1481. return curr != nullptr;
  1482. }
  1483. IConstMachineInfo & CConstMachineInfoIterator::query()
  1484. {
  1485. return *curr;
  1486. }
  1487. unsigned CConstMachineInfoIterator::count() const
  1488. {
  1489. return maxIndex;
  1490. }
  1491. CConstDropZoneServerInfoIterator::CConstDropZoneServerInfoIterator(const IConstDropZoneInfo * dropZone)
  1492. {
  1493. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  1494. constEnv.setown((CLocalEnvironment *)factory->openEnvironment());
  1495. // For backward compatibility
  1496. SCMStringBuffer dropZoneMachineName;
  1497. // Returns dropzone '@computer' value if it is exists
  1498. dropZone->getComputerName(dropZoneMachineName);
  1499. if (0 != dropZoneMachineName.length())
  1500. {
  1501. // Create a ServerList for legacy element.
  1502. Owned<IPropertyTree> legacyServerList = createPTree(ipt_lowmem);
  1503. Owned<IConstMachineInfo> machineInfo = constEnv->getMachine(dropZoneMachineName.str());
  1504. if (machineInfo)
  1505. {
  1506. SCMStringBuffer dropZoneMachineNetAddress;
  1507. machineInfo->getNetAddress(dropZoneMachineNetAddress);
  1508. // Create a single ServerList record related to @computer
  1509. //<ServerList name="ServerList" server="<IP_of_@computer>"/>
  1510. IPropertyTree *newRecord = legacyServerList->addPropTree("ServerList");
  1511. newRecord->setProp("@name", "ServerList");
  1512. newRecord->setProp("@server", dropZoneMachineNetAddress.str());
  1513. maxIndex = 1;
  1514. }
  1515. else
  1516. {
  1517. // Something is terrible wrong because there is no matching machine for DropZone @computer
  1518. maxIndex = 0;
  1519. }
  1520. serverListIt.setown(legacyServerList->getElements("ServerList"));
  1521. }
  1522. else
  1523. {
  1524. Owned<IPropertyTree> pSrc = &dropZone->getPTree();
  1525. serverListIt.setown(pSrc->getElements("ServerList"));
  1526. maxIndex = pSrc->getCount("ServerList");
  1527. }
  1528. }
  1529. bool CConstDropZoneServerInfoIterator::first()
  1530. {
  1531. bool hasFirst = serverListIt->first();
  1532. if (hasFirst)
  1533. curr.setown(new CConstDropZoneServerInfo(constEnv, &serverListIt->query()));
  1534. else
  1535. curr.clear();
  1536. return hasFirst;
  1537. }
  1538. bool CConstDropZoneServerInfoIterator::next()
  1539. {
  1540. bool hasNext = serverListIt->next();
  1541. if (hasNext)
  1542. curr.setown(new CConstDropZoneServerInfo(constEnv, &serverListIt->query()));
  1543. else
  1544. curr.clear();
  1545. return hasNext;
  1546. }
  1547. bool CConstDropZoneServerInfoIterator::isValid()
  1548. {
  1549. return nullptr != curr;
  1550. }
  1551. IConstDropZoneServerInfo & CConstDropZoneServerInfoIterator::query()
  1552. {
  1553. return *curr;
  1554. }
  1555. unsigned CConstDropZoneServerInfoIterator::count() const
  1556. {
  1557. return maxIndex;
  1558. }
  1559. //--------------------------------------------------
  1560. CConstDropZoneInfoIterator::CConstDropZoneInfoIterator()
  1561. {
  1562. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  1563. constEnv.setown((CLocalEnvironment *)factory->openEnvironment());
  1564. maxIndex = constEnv->getNumberOfDropZones();
  1565. }
  1566. bool CConstDropZoneInfoIterator::first()
  1567. {
  1568. index = 1;
  1569. curr.setown(constEnv->getDropZoneByIndex(index));
  1570. return curr != nullptr;
  1571. }
  1572. bool CConstDropZoneInfoIterator::next()
  1573. {
  1574. if (index < maxIndex)
  1575. {
  1576. index++;
  1577. curr.setown(constEnv->getDropZoneByIndex(index));
  1578. }
  1579. else
  1580. curr.clear();
  1581. return curr != nullptr;
  1582. }
  1583. bool CConstDropZoneInfoIterator::isValid()
  1584. {
  1585. return curr != nullptr;
  1586. }
  1587. IConstDropZoneInfo & CConstDropZoneInfoIterator::query()
  1588. {
  1589. return *curr;
  1590. }
  1591. unsigned CConstDropZoneInfoIterator::count() const
  1592. {
  1593. return maxIndex;
  1594. }
  1595. //==========================================================================================
  1596. static CriticalSection getEnvSect;
  1597. extern ENVIRONMENT_API IEnvironmentFactory * getEnvironmentFactory(bool update)
  1598. {
  1599. CriticalBlock block(getEnvSect);
  1600. if (!factory)
  1601. {
  1602. factory = new CEnvironmentFactory();
  1603. addShutdownHook(*factory);
  1604. }
  1605. if (update)
  1606. factory->validateCache();
  1607. return LINK(factory);
  1608. }
  1609. extern ENVIRONMENT_API void closeEnvironment()
  1610. {
  1611. try
  1612. {
  1613. CEnvironmentFactory* pFactory;
  1614. {
  1615. //this method is not meant to be invoked by multiple
  1616. //threads concurrently but just in case...
  1617. CriticalBlock block(getEnvSect);
  1618. pFactory = factory;
  1619. factory = nullptr;
  1620. }
  1621. clearPasswordsFromSDS();
  1622. if (pFactory)
  1623. {
  1624. removeShutdownHook(*pFactory);
  1625. pFactory->close();
  1626. pFactory->Release();
  1627. }
  1628. }
  1629. catch (IException *e)
  1630. {
  1631. EXCLOG(e);
  1632. }
  1633. }