daserver.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  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 <unordered_map>
  14. #include <string>
  15. #include "platform.h"
  16. #include "thirdparty.h"
  17. #include "jlib.hpp"
  18. #include "jlog.ipp"
  19. #include "jptree.hpp"
  20. #include "jmisc.hpp"
  21. #include "jutil.hpp"
  22. #include "jmetrics.hpp"
  23. #include "mpbase.hpp"
  24. #include "mpcomm.hpp"
  25. #include "mplog.hpp" //MORE: deprecated feature, not used by any new clients, remove once all deployed clients that depend on it are upgraded
  26. #include "rmtfile.hpp"
  27. #include "dacoven.hpp"
  28. #include "dadfs.hpp"
  29. #include "dasess.hpp"
  30. #include "daaudit.hpp"
  31. #include "dasds.hpp"
  32. #include "daclient.hpp"
  33. #include "dasubs.ipp"
  34. #include "danqs.hpp"
  35. #include "dadiags.hpp"
  36. #ifdef _DEBUG
  37. //#define DALI_MIN
  38. #endif
  39. #ifdef DALI_MIN
  40. #define _NO_LDAP
  41. #endif
  42. #include "daserver.hpp"
  43. #ifndef _NO_LDAP
  44. #include "daldap.hpp"
  45. #endif
  46. Owned<IPropertyTree> serverConfig;
  47. static IArrayOf<IDaliServer> servers;
  48. static CriticalSection *stopServerCrit;
  49. MODULE_INIT(INIT_PRIORITY_DALI_DASERVER)
  50. {
  51. stopServerCrit = new CriticalSection;
  52. return true;
  53. }
  54. MODULE_EXIT()
  55. {
  56. servers.kill(); // should already be clear when stopped
  57. serverConfig.clear();
  58. delete stopServerCrit;
  59. }
  60. #define DEFAULT_PERF_REPORT_DELAY 60
  61. #define DEFAULT_MOUNT_POINT "/mnt/dalimirror/"
  62. void setMsgLevel(ILogMsgHandler * fileMsgHandler, unsigned level)
  63. {
  64. ILogMsgFilter *filter = getSwitchLogMsgFilterOwn(getComponentLogMsgFilter(3), getCategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, level, true), getDefaultLogMsgFilter());
  65. queryLogMsgManager()->changeMonitorFilter(queryStderrLogMsgHandler(), filter);
  66. queryLogMsgManager()->changeMonitorFilterOwn(fileMsgHandler, filter);
  67. }
  68. void AddServers(const char *auditdir)
  69. {
  70. // order significant
  71. servers.append(*createDaliSessionServer());
  72. servers.append(*createDaliPublisherServer());
  73. servers.append(*createDaliSDSServer(serverConfig));
  74. servers.append(*createDaliNamedQueueServer());
  75. servers.append(*createDaliDFSServer(serverConfig));
  76. servers.append(*createDaliAuditServer(auditdir));
  77. servers.append(*createDaliDiagnosticsServer());
  78. // add new coven servers here
  79. }
  80. static bool serverStopped = false;
  81. static void stopServer()
  82. {
  83. CriticalBlock b(*stopServerCrit); // NB: will not protect against abort handler, which will interrupt thread and be on same TID.
  84. if (serverStopped) return;
  85. serverStopped = true;
  86. ForEachItemInRev(h,servers)
  87. {
  88. IDaliServer &server=servers.item(h);
  89. LOG(MCprogress, unknownJob, "Suspending %d",h);
  90. server.suspend();
  91. }
  92. ForEachItemInRev(i,servers)
  93. {
  94. IDaliServer &server=servers.item(i);
  95. LOG(MCprogress, unknownJob, "Stopping %d",i);
  96. server.stop();
  97. }
  98. closeCoven();
  99. ForEachItemInRev(j,servers)
  100. {
  101. servers.remove(j); // ensure correct order for destruction
  102. }
  103. stopLogMsgReceivers(); //MORE: deprecated feature, not used by any new clients, remove once all deployed clients that depend on it are upgraded
  104. stopMPServer();
  105. }
  106. bool actionOnAbort()
  107. {
  108. stopServer();
  109. return true;
  110. }
  111. USE_JLIB_ALLOC_HOOK;
  112. void usage(void)
  113. {
  114. printf("daserver (option)\n");
  115. printf("--rank|-r <value>\t: dali ranking value\n");
  116. printf("--server|-s <value>\t: server ip if not local host\n");
  117. printf("--port|-p <value>\t: server port only effective if --server set\n");
  118. printf("--daemon|-d <instanceName>\t: run daemon as instance\n");
  119. }
  120. static IPropertyTree *getSecMgrPluginPropTree(const IPropertyTree *configTree)
  121. {
  122. Owned<IPropertyTree> foundTree;
  123. #ifdef _CONTAINERIZED
  124. // TODO
  125. #else
  126. Owned<IRemoteConnection> conn = querySDS().connect("/Environment", 0, 0, INFINITE);
  127. if (conn)
  128. {
  129. const IPropertyTree *proptree = conn->queryRoot()->queryPropTree("Software/DaliServerProcess[1]");
  130. if (proptree)
  131. {
  132. const char* authMethod = proptree->queryProp("@authMethod");
  133. if (strisame(authMethod, "secmgrPlugin"))
  134. {
  135. const char* authPluginType = proptree->queryProp("@authPluginType");
  136. if (authPluginType)
  137. {
  138. VStringBuffer xpath("SecurityManagers/SecurityManager[@name='%s']", authPluginType);
  139. foundTree.setown(configTree->getPropTree(xpath));
  140. if (!foundTree.get())
  141. {
  142. WARNLOG("secmgPlugin '%s' not defined in configuration", authPluginType);
  143. }
  144. }
  145. }
  146. }
  147. }
  148. #endif
  149. return foundTree.getClear();
  150. }
  151. /* NB: Ideally this belongs within common/environment,
  152. * however, that would introduce a circular dependency.
  153. */
  154. static bool populateAllowListFromEnvironment(IAllowListWriter &writer)
  155. {
  156. Owned<IRemoteConnection> conn = querySDS().connect("/Environment", 0, 0, INFINITE);
  157. assertex(conn);
  158. if (!conn->queryRoot()->hasProp("Software/DaliServerProcess"))
  159. return false;
  160. // only ever expecting 1 DaliServerProcess and 1 AllowList
  161. const IPropertyTree *allowListTree = conn->queryRoot()->queryPropTree("Software/DaliServerProcess[1]/AllowList[1]");
  162. if (!allowListTree)
  163. {
  164. // deprecated, but for backward compatibility..
  165. allowListTree = conn->queryRoot()->queryPropTree("Software/DaliServerProcess[1]/WhiteList[1]");
  166. }
  167. bool enabled = true;
  168. if (allowListTree)
  169. {
  170. enabled = allowListTree->getPropBool("@enabled", true); // on by default
  171. // Default for now is to allow clients that send no role (legacy) to connect if their IP is in allowlist.
  172. writer.setAllowAnonRoles(allowListTree->getPropBool("@allowAnonRoles", true));
  173. }
  174. std::unordered_map<std::string, std::string> machineMap;
  175. auto populateMachineMap = [&machineMap](const IPropertyTree &environment)
  176. {
  177. Owned<IPropertyTreeIterator> machineIter = environment.getElements("Hardware/Computer");
  178. ForEach(*machineIter)
  179. {
  180. const IPropertyTree &machine = machineIter->query();
  181. const char *name = machine.queryProp("@name");
  182. const char *host = machine.queryProp("@netAddress");
  183. machineMap.insert({name, host});
  184. }
  185. };
  186. auto resolveComputer = [&machineMap](const char *compName, const char *defaultValue, StringBuffer &result) -> const char *
  187. {
  188. const auto &it = machineMap.find(compName);
  189. if (it == machineMap.end())
  190. return defaultValue;
  191. IpAddress ip(it->second.c_str());
  192. if (ip.isNull())
  193. return defaultValue;
  194. return ip.getIpText(result);
  195. };
  196. auto addRoles = [&writer, &resolveComputer](const IPropertyTree &component, const std::initializer_list<unsigned __int64> &roles)
  197. {
  198. Owned<IPropertyTreeIterator> instanceIter = component.getElements("Instance");
  199. ForEach(*instanceIter)
  200. {
  201. const char *compName = instanceIter->query().queryProp("@computer");
  202. StringBuffer ipSB;
  203. const char *ip = resolveComputer(compName, component.queryProp("@netAddress"), ipSB);
  204. if (ip)
  205. {
  206. for (const auto &role: roles)
  207. writer.add(ip, role);
  208. }
  209. }
  210. };
  211. populateMachineMap(*conn->queryRoot());
  212. enum SoftwareComponentType
  213. {
  214. RoxieCluster,
  215. ThorCluster,
  216. EclAgentProcess,
  217. DfuServerProcess,
  218. EclCCServerProcess,
  219. EspProcess,
  220. SashaServerProcess,
  221. EclSchedulerProcess,
  222. DaliServerProcess,
  223. BackupNodeProcess,
  224. EclServerProcess,
  225. SparkThorProcess,
  226. };
  227. std::unordered_map<std::string, SoftwareComponentType> softwareTypeRoleMap = {
  228. { "RoxieCluster", RoxieCluster },
  229. { "ThorCluster", ThorCluster },
  230. { "EclAgentProcess", EclAgentProcess },
  231. { "DfuServerProcess", DfuServerProcess },
  232. { "EclCCServerProcess", EclCCServerProcess },
  233. { "EspProcess", EspProcess },
  234. { "SashaServerProcess", SashaServerProcess },
  235. { "EclSchedulerProcess", EclSchedulerProcess },
  236. { "DaliServerProcess", DaliServerProcess },
  237. { "BackupNodeProcess", BackupNodeProcess },
  238. { "EclServerProcess", EclServerProcess },
  239. { "SparkThorProcess", SparkThorProcess },
  240. };
  241. Owned<IPropertyTreeIterator> softwareIter = conn->queryRoot()->getElements("Software/*");
  242. ForEach(*softwareIter)
  243. {
  244. const IPropertyTree &component = softwareIter->query();
  245. const char *compProcess = component.queryName();
  246. const auto &it = softwareTypeRoleMap.find(compProcess);
  247. if (it != softwareTypeRoleMap.end())
  248. {
  249. switch (it->second)
  250. {
  251. case RoxieCluster:
  252. {
  253. Owned<IPropertyTreeIterator> serverIter = component.getElements("RoxieServerProcess");
  254. ForEach(*serverIter)
  255. {
  256. const IPropertyTree &server = serverIter->query();
  257. const char *serverCompName = server.queryProp("@computer");
  258. StringBuffer ipSB;
  259. const char *ip = resolveComputer(serverCompName, server.queryProp("@netAddress"), ipSB);
  260. if (ip)
  261. writer.add(ip, DCR_Roxie);
  262. }
  263. break;
  264. }
  265. case ThorCluster:
  266. {
  267. const char *masterCompName = component.queryProp("ThorMasterProcess/@computer");
  268. StringBuffer ipSB;
  269. const char *ip = resolveComputer(masterCompName, nullptr, ipSB);
  270. if (ip)
  271. {
  272. writer.add(ip, DCR_ThorMaster);
  273. writer.add(ip, DCR_DaliAdmin);
  274. }
  275. // NB: slaves are currently seen as foreign clients and are only used by Std.File.GetUniqueInteger (which calls Dali v. occassionally)
  276. Owned<IPropertyTreeIterator> slaveIter = component.getElements("ThorSlaveProcess");
  277. ForEach(*slaveIter)
  278. {
  279. const char *slaveCompName = slaveIter->query().queryProp("@computer");
  280. const char *ip = resolveComputer(slaveCompName, nullptr, ipSB.clear());
  281. if (ip)
  282. writer.add(ip, DCR_ThorSlave);
  283. }
  284. break;
  285. }
  286. case EclAgentProcess:
  287. addRoles(component, { DCR_EclAgent, DCR_AgentExec });
  288. break;
  289. case DfuServerProcess:
  290. addRoles(component, { DCR_DfuServer });
  291. break;
  292. case EclCCServerProcess:
  293. addRoles(component, { DCR_EclCCServer, DCR_EclCC });
  294. break;
  295. case EclServerProcess:
  296. addRoles(component, { DCR_EclServer, DCR_EclCC });
  297. break;
  298. case EspProcess:
  299. addRoles(component, { DCR_EspServer });
  300. break;
  301. case SashaServerProcess:
  302. addRoles(component, { DCR_SashaServer, DCR_XRef });
  303. break;
  304. case EclSchedulerProcess:
  305. addRoles(component, { DCR_EclScheduler });
  306. break;
  307. case BackupNodeProcess:
  308. addRoles(component, { DCR_BackupGen, DCR_DaliAdmin });
  309. break;
  310. case DaliServerProcess:
  311. addRoles(component, { DCR_DaliServer, DCR_DaliDiag, DCR_SwapNode, DCR_UpdateEnv, DCR_DaliAdmin, DCR_TreeView, DCR_Testing, DCR_DaFsControl, DCR_XRef, DCR_Config, DCR_ScheduleAdmin, DCR_Monitoring, DCR_DaliStop });
  312. break;
  313. case SparkThorProcess:
  314. addRoles(component, { DCR_DaliAdmin });
  315. break;
  316. }
  317. }
  318. }
  319. if (allowListTree)
  320. {
  321. Owned<IPropertyTreeIterator> allowListIter = allowListTree->getElements("Entry");
  322. ForEach(*allowListIter)
  323. {
  324. const IPropertyTree &entry = allowListIter->query();
  325. StringArray hosts, roles;
  326. hosts.appendListUniq(entry.queryProp("@hosts"), ",");
  327. roles.appendListUniq(entry.queryProp("@roles"), ",");
  328. ForEachItemIn(h, hosts)
  329. {
  330. IpAddress ip(hosts.item(h));
  331. if (!ip.isNull())
  332. {
  333. StringBuffer ipStr;
  334. ip.getIpText(ipStr);
  335. ForEachItemIn(r, roles)
  336. {
  337. const char *roleStr = roles.item(r);
  338. char *endPtr;
  339. long numericRole = strtol(roleStr, &endPtr, 10);
  340. if (endPtr != roleStr && (numericRole>0 && numericRole<DCR_Max)) // in case legacy role needs adding
  341. writer.add(ipStr.str(), numericRole);
  342. else
  343. writer.add(ipStr.str(), queryRole(roleStr));
  344. }
  345. }
  346. }
  347. }
  348. }
  349. return enabled;
  350. }
  351. static StringBuffer &formatDaliRole(StringBuffer &out, unsigned __int64 role)
  352. {
  353. return out.append(queryRoleName((DaliClientRole)role));
  354. }
  355. #ifdef _CONTAINERIZED
  356. static IPropertyTree * getContainerLDAPConfiguration(const IPropertyTree *appConfig)
  357. {
  358. const char * authMethod = appConfig->queryProp("@auth");
  359. if (streq(authMethod, "none"))
  360. {
  361. WARNLOG("ECLWatch is unsafe, no security manager specified in configuration (auth: none)");
  362. return nullptr; //no security manager
  363. }
  364. if (!streq(authMethod, "ldap"))
  365. {
  366. throw makeStringExceptionV(-1, "Unrecognized auth method specified, (auth: %s)", authMethod);
  367. }
  368. //Get default LDAP attributes from ldap.yaml
  369. StringBuffer ldapDefaultsFile(hpccBuildInfo.componentDir);
  370. char sepchar = getPathSepChar(ldapDefaultsFile.str());
  371. addPathSepChar(ldapDefaultsFile, sepchar).append("applications").append(sepchar).append("common").append(sepchar).append("ldap").append(sepchar).append("ldap.yaml");
  372. Owned<IPropertyTree> defaults;
  373. if (!checkFileExists(ldapDefaultsFile))
  374. {
  375. throw makeStringExceptionV(-1, "Unable to locate LDAP defaults file '%s'", ldapDefaultsFile.str());
  376. }
  377. defaults.setown(createPTreeFromYAMLFile(ldapDefaultsFile.str()));
  378. //Build merged configuration
  379. Owned<IPropertyTree> mergedConfig = defaults->getPropTree("ldap");
  380. mergeConfiguration(*mergedConfig, *appConfig->queryPropTree("ldap"));
  381. return LINK(mergedConfig);
  382. }
  383. #endif
  384. static constexpr const char * defaultYaml = R"!!(
  385. version: 1.0
  386. dali:
  387. name: dali
  388. dataPath: "/var/lib/HPCCSystems/dalistorage"
  389. )!!";
  390. //
  391. // Initialize metrics
  392. static void initializeMetrics(IPropertyTree *pConfig)
  393. {
  394. //
  395. // Initialize metrics if present
  396. Owned<IPropertyTree> pMetricsTree = pConfig->getPropTree("metrics");
  397. if (pMetricsTree != nullptr)
  398. {
  399. PROGLOG("Metrics initializing...");
  400. hpccMetrics::MetricsManager &metricsManager = hpccMetrics::queryMetricsManager();
  401. metricsManager.init(pMetricsTree);
  402. metricsManager.startCollecting();
  403. }
  404. }
  405. int main(int argc, const char* argv[])
  406. {
  407. rank_t myrank = 0;
  408. const char *server = nullptr;
  409. int port = 0;
  410. InitModuleObjects();
  411. NoQuickEditSection x;
  412. try
  413. {
  414. EnableSEHtoExceptionMapping();
  415. #ifndef __64BIT__
  416. // Restrict stack sizes on 32-bit systems
  417. Thread::setDefaultStackSize(0x20000);
  418. #endif
  419. setAllocHook(true);
  420. serverConfig.setown(loadConfiguration(defaultYaml, argv, "dali", "DALI", DALICONF, nullptr));
  421. Owned<IFile> sentinelFile = createSentinelTarget();
  422. removeSentinelFile(sentinelFile);
  423. port = serverConfig->getPropInt("@port");
  424. #ifndef _CONTAINERIZED
  425. if (!checkCreateDaemon(argc, argv))
  426. return EXIT_FAILURE;
  427. for (unsigned i=1;i<(unsigned)argc;i++) {
  428. if (streq(argv[i],"--daemon") || streq(argv[i],"-d")) {
  429. i++; // consumed within checkCreateDaemon(), bump up here
  430. }
  431. else if (streq(argv[i],"--server") || streq(argv[i],"-s"))
  432. server = argv[++i];
  433. else if (streq(argv[i],"--port") || streq(argv[i],"-p"))
  434. port = atoi(argv[++i]);
  435. else if (streq(argv[i],"--rank") || streq(argv[i],"-r"))
  436. myrank = atoi(argv[++i]);
  437. else if (!startsWith(argv[i],"--config"))
  438. {
  439. usage();
  440. return EXIT_FAILURE;
  441. }
  442. }
  443. #endif
  444. #ifndef _CONTAINERIZED
  445. ILogMsgHandler * fileMsgHandler;
  446. {
  447. Owned<IComponentLogFileCreator> lf = createComponentLogFileCreator(serverConfig, "dali");
  448. lf->setLogDirSubdir("server");//add to tail of config log dir
  449. lf->setName("DaServer");//override default filename
  450. fileMsgHandler = lf->beginLogging();
  451. }
  452. #else
  453. setupContainerizedLogMsgHandler();
  454. #endif
  455. PROGLOG("Build %s", hpccBuildInfo.buildTag);
  456. StringBuffer dataPath;
  457. StringBuffer mirrorPath;
  458. #ifdef _CONTAINERIZED
  459. serverConfig->getProp("@dataPath", dataPath);
  460. /* NB: mirror settings are unlikely to be used in a container setup
  461. If detected, set in to legacy location under SDS/ for backward compatibility */
  462. serverConfig->getProp("@remoteBackupLocation", mirrorPath);
  463. if (mirrorPath.length())
  464. serverConfig->setProp("SDS/@remoteBackupLocation", mirrorPath);
  465. #else
  466. if (getConfigurationDirectory(serverConfig->queryPropTree("Directories"),"dali","dali",serverConfig->queryProp("@name"),dataPath))
  467. serverConfig->setProp("@dataPath",dataPath.str());
  468. else if (getConfigurationDirectory(serverConfig->queryPropTree("Directories"),"data","dali",serverConfig->queryProp("@name"),dataPath))
  469. serverConfig->setProp("@dataPath",dataPath.str());
  470. else
  471. serverConfig->getProp("@dataPath",dataPath);
  472. if (dataPath.length())
  473. {
  474. RemoteFilename rfn;
  475. rfn.setRemotePath(dataPath);
  476. if (!rfn.isLocal())
  477. {
  478. OERRLOG("if a dataPath is specified, it must be on local machine");
  479. return 0;
  480. }
  481. }
  482. // JCSMORE remoteBackupLocation should not be a property of SDS section really.
  483. if (!getConfigurationDirectory(serverConfig->queryPropTree("Directories"),"mirror","dali",serverConfig->queryProp("@name"),mirrorPath))
  484. serverConfig->getProp("SDS/@remoteBackupLocation",mirrorPath);
  485. #endif
  486. if (dataPath.length())
  487. {
  488. addPathSepChar(dataPath); // ensures trailing path separator
  489. serverConfig->setProp("@dataPath", dataPath.str());
  490. recursiveCreateDirectory(dataPath.str());
  491. }
  492. if (mirrorPath.length())
  493. {
  494. try
  495. {
  496. addPathSepChar(mirrorPath);
  497. try
  498. {
  499. StringBuffer backupURL;
  500. if (mirrorPath.length()<=2 || !isPathSepChar(mirrorPath.charAt(0)) || !isPathSepChar(mirrorPath.charAt(1)))
  501. { // local machine path, convert to url
  502. const char *backupnode = serverConfig->queryProp("SDS/@backupComputer");
  503. RemoteFilename rfn;
  504. if (backupnode&&*backupnode) {
  505. SocketEndpoint ep(backupnode);
  506. rfn.setPath(ep,mirrorPath.str());
  507. }
  508. else {
  509. OWARNLOG("Local path used for backup url: %s", mirrorPath.str());
  510. rfn.setLocalPath(mirrorPath.str());
  511. }
  512. rfn.getRemotePath(backupURL);
  513. mirrorPath.clear().append(backupURL);
  514. }
  515. else
  516. backupURL.append(mirrorPath);
  517. recursiveCreateDirectory(backupURL.str());
  518. addPathSepChar(backupURL);
  519. serverConfig->setProp("SDS/@remoteBackupLocation", backupURL.str());
  520. PROGLOG("Backup URL = %s", backupURL.str());
  521. }
  522. catch (IException *e)
  523. {
  524. EXCLOG(e, "Failed to create remote backup directory, disabling backups", MSGCLS_warning);
  525. serverConfig->removeProp("SDS/@remoteBackupLocation");
  526. mirrorPath.clear();
  527. e->Release();
  528. }
  529. if (mirrorPath.length())
  530. {
  531. PROGLOG("Checking backup location: %s", mirrorPath.str());
  532. #if defined(__linux__)
  533. if (serverConfig->getPropBool("@useNFSBackupMount", false))
  534. {
  535. RemoteFilename rfn;
  536. if (mirrorPath.length()<=2 || !isPathSepChar(mirrorPath.charAt(0)) || !isPathSepChar(mirrorPath.charAt(1)))
  537. rfn.setLocalPath(mirrorPath.str());
  538. else
  539. rfn.setRemotePath(mirrorPath.str());
  540. if (!rfn.getPort() && !rfn.isLocal())
  541. {
  542. StringBuffer mountPoint;
  543. serverConfig->getProp("@mountPoint", mountPoint);
  544. if (!mountPoint.length())
  545. mountPoint.append(DEFAULT_MOUNT_POINT);
  546. addPathSepChar(mountPoint);
  547. recursiveCreateDirectory(mountPoint.str());
  548. PROGLOG("Mounting url \"%s\" on mount point \"%s\"", mirrorPath.str(), mountPoint.str());
  549. bool ub = unmountDrive(mountPoint.str());
  550. if (!mountDrive(mountPoint.str(), rfn))
  551. {
  552. if (!ub)
  553. PROGLOG("Failed to remount mount point \"%s\", possibly in use?", mountPoint.str());
  554. else
  555. PROGLOG("Failed to mount \"%s\"", mountPoint.str());
  556. return 0;
  557. }
  558. else
  559. serverConfig->setProp("SDS/@remoteBackupLocation", mountPoint.str());
  560. mirrorPath.clear().append(mountPoint);
  561. }
  562. }
  563. #endif
  564. StringBuffer backupCheck(dataPath);
  565. backupCheck.append("bakchk.").append((unsigned)GetCurrentProcessId());
  566. OwnedIFile iFileDataDir = createIFile(backupCheck.str());
  567. OwnedIFileIO iFileIO = iFileDataDir->open(IFOcreate);
  568. iFileIO.clear();
  569. try
  570. {
  571. backupCheck.clear().append(mirrorPath).append("bakchk.").append((unsigned)GetCurrentProcessId());
  572. OwnedIFile iFileBackup = createIFile(backupCheck.str());
  573. if (iFileBackup->exists())
  574. {
  575. PROGLOG("remoteBackupLocation and dali data path point to same location! : %s", mirrorPath.str());
  576. iFileDataDir->remove();
  577. return 0;
  578. }
  579. }
  580. catch (IException *)
  581. {
  582. try { iFileDataDir->remove(); } catch (IException *e) { EXCLOG(e, NULL); e->Release(); }
  583. throw;
  584. }
  585. iFileDataDir->remove();
  586. #ifndef _CONTAINERIZED
  587. StringBuffer dest(mirrorPath.str());
  588. dest.append(DALICONF);
  589. copyFile(dest.str(), DALICONF);
  590. StringBuffer covenPath(dataPath);
  591. OwnedIFile ifile = createIFile(covenPath.append(DALICOVEN).str());
  592. if (ifile->exists())
  593. {
  594. dest.clear().append(mirrorPath.str()).append(DALICOVEN);
  595. copyFile(dest.str(), covenPath.str());
  596. }
  597. #endif
  598. }
  599. if (serverConfig->getPropBool("@daliServixCaching", true))
  600. setDaliServixSocketCaching(true);
  601. }
  602. catch (IException *e)
  603. {
  604. StringBuffer s("Failure whilst preparing dali backup location: ");
  605. LOG(MCoperatorError, unknownJob, e, s.append(mirrorPath).append(". Backup disabled").str());
  606. serverConfig->removeProp("SDS/@remoteBackupLocation");
  607. e->Release();
  608. }
  609. }
  610. #ifndef _CONTAINERIZED
  611. write_pidfile(serverConfig->queryProp("@name"));
  612. NamedMutex globalNamedMutex("DASERVER");
  613. if (!serverConfig->getPropBool("allowMultipleDalis"))
  614. {
  615. PROGLOG("Checking for existing daserver instances");
  616. if (!globalNamedMutex.lockWait(0))
  617. {
  618. OWARNLOG("Another DASERVER process is currently running");
  619. return 0;
  620. }
  621. }
  622. #endif
  623. SocketEndpoint ep;
  624. SocketEndpointArray epa;
  625. if (!server)
  626. {
  627. ep.setLocalHost(port ? port : DALI_SERVER_PORT);
  628. epa.append(ep);
  629. }
  630. else
  631. {
  632. if (!port)
  633. ep.set(server,DALI_SERVER_PORT);
  634. else
  635. ep.set(server,port);
  636. epa.append(ep);
  637. }
  638. unsigned short myport = epa.item(myrank).port;
  639. startMPServer(DCR_DaliServer, myport, true, true);
  640. #ifndef _CONTAINERIZED
  641. Owned<IMPServer> mpServer = getMPServer();
  642. Owned<IAllowListHandler> allowListHandler = createAllowListHandler(populateAllowListFromEnvironment, formatDaliRole);
  643. mpServer->installAllowListCallback(allowListHandler);
  644. setMsgLevel(fileMsgHandler, serverConfig->getPropInt("SDS/@msgLevel", DebugMsgThreshold));
  645. #endif
  646. startLogMsgChildReceiver();
  647. startLogMsgParentReceiver();
  648. IGroup *group = createIGroup(epa);
  649. initCoven(group,serverConfig);
  650. group->Release();
  651. epa.kill();
  652. // Audit logging
  653. StringBuffer auditDir;
  654. {
  655. //MORE: Does this need to change in CONTAINERIZED mode?
  656. Owned<IComponentLogFileCreator> lf = createComponentLogFileCreator(serverConfig, "dali");
  657. lf->setLogDirSubdir("audit");//add to tail of config log dir
  658. lf->setName("DaAudit");//override default filename
  659. lf->setCreateAliasFile(false);
  660. lf->setMsgFields(MSGFIELD_timeDate | MSGFIELD_code | MSGFIELD_job);
  661. lf->setMsgAudiences(MSGAUD_audit);
  662. lf->setMaxDetail(TopDetail);
  663. lf->beginLogging();
  664. auditDir.set(lf->queryLogDir());
  665. }
  666. // SNMP logging
  667. bool enableSNMP = serverConfig->getPropBool("SDS/@enableSNMP");
  668. if (serverConfig->getPropBool("SDS/@enableSysLog",true))
  669. UseSysLogForOperatorMessages();
  670. AddServers(auditDir.str());
  671. addAbortHandler(actionOnAbort);
  672. #ifndef _CONTAINERIZED
  673. startPerformanceMonitor(serverConfig->getPropInt("Coven/@perfReportDelay", DEFAULT_PERF_REPORT_DELAY)*1000);
  674. #endif
  675. StringBuffer absPath;
  676. makeAbsolutePath(dataPath.str(), absPath);
  677. setPerformanceMonitorPrimaryFileSystem(absPath.str());
  678. if (mirrorPath.length())
  679. {
  680. absPath.clear();
  681. makeAbsolutePath(mirrorPath.str(), absPath);
  682. setPerformanceMonitorSecondaryFileSystem(absPath.str());
  683. }
  684. try
  685. {
  686. ForEachItemIn(i1,servers)
  687. {
  688. IDaliServer &server=servers.item(i1);
  689. server.start();
  690. }
  691. }
  692. catch (IException *e)
  693. {
  694. EXCLOG(e, "Failed whilst starting servers");
  695. stopServer();
  696. #ifndef _CONTAINERIZED
  697. stopPerformanceMonitor();
  698. #endif
  699. throw;
  700. }
  701. try {
  702. #ifndef _NO_LDAP
  703. Owned<IPropertyTree> secMgrPropTree = getSecMgrPluginPropTree(serverConfig);
  704. if (secMgrPropTree.get())
  705. {
  706. setLDAPconnection(createDaliSecMgrPluginConnection(secMgrPropTree));
  707. }
  708. else
  709. {
  710. #ifdef _CONTAINERIZED
  711. setLDAPconnection(createDaliLdapConnection(getContainerLDAPConfiguration(serverConfig)));//container configuration
  712. #else
  713. setLDAPconnection(createDaliLdapConnection(serverConfig->getPropTree("Coven/ldapSecurity")));//legacy configuration
  714. #endif
  715. }
  716. #endif
  717. }
  718. catch (IException *e) {
  719. EXCLOG(e, "LDAP initialization error");
  720. stopServer();
  721. #ifndef _CONTAINERIZED
  722. stopPerformanceMonitor();
  723. #endif
  724. throw;
  725. }
  726. PROGLOG("DASERVER[%d] starting - listening to port %d",myrank,queryMyNode()->endpoint().port);
  727. startMPServer(DCR_DaliServer, myport, false, true);
  728. bool ok = true;
  729. ForEachItemIn(i2,servers)
  730. {
  731. IDaliServer &server=servers.item(i2);
  732. try {
  733. server.ready();
  734. }
  735. catch (IException *e) {
  736. EXCLOG(e,"Exception starting Dali Server");
  737. ok = false;
  738. }
  739. }
  740. if (ok) {
  741. writeSentinelFile(sentinelFile);
  742. initializeMetrics(serverConfig);
  743. covenMain();
  744. removeAbortHandler(actionOnAbort);
  745. }
  746. stopServer();
  747. #ifndef _CONTAINERIZED
  748. stopPerformanceMonitor();
  749. #endif
  750. }
  751. catch (IException *e) {
  752. EXCLOG(e, "Exception");
  753. }
  754. UseSysLogForOperatorMessages(false);
  755. return 0;
  756. }