otsdaq  v2_03_00
CorePropertySupervisorBase.cc
1 #include "otsdaq-core/CoreSupervisors/CorePropertySupervisorBase.h"
2 
3 using namespace ots;
4 
6  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES =
8 
9 //========================================================================================================================
10 CorePropertySupervisorBase::CorePropertySupervisorBase(xdaq::Application* application)
11  : theConfigurationManager_(new ConfigurationManager)
12  , supervisorClass_(application->getApplicationDescriptor()->getClassName())
13  , supervisorClassNoNamespace_(supervisorClass_.substr(
14  supervisorClass_.find_last_of(":") + 1,
15  supervisorClass_.length() - supervisorClass_.find_last_of(":")))
16  , supervisorContextUID_(
17  "UNINITIALIZED_supervisorContextUID") // MUST BE INITIALIZED
18  // INSIDE THE CONTRUCTOR
19  // TO THROW EXCEPTIONS
20  // on bad conditions
21  , supervisorApplicationUID_(
22  "UNINITIALIZED_supervisorApplicationUID") // MUST BE INITIALIZED INSIDE THE
23  // CONTRUCTOR TO THROW EXCEPTIONS on
24  // bad conditions
25  , supervisorConfigurationPath_(
26  "UNINITIALIZED_supervisorConfigurationPath") // MUST BE INITIALIZED INSIDE THE
27  // CONTRUCTOR TO THROW EXCEPTIONS
28  // on bad conditions
29  , propertiesAreSetup_(false)
30 {
31  INIT_MF("CorePropertySupervisorBase");
32 
33  __SUP_COUTV__(application->getApplicationContext()->getContextDescriptor()->getURL());
34  __SUP_COUTV__(application->getApplicationDescriptor()->getLocalId());
35  __SUP_COUTV__(supervisorClass_);
36  __SUP_COUTV__(supervisorClassNoNamespace_);
37 
38  // get all supervisor info, and wiz mode or not
39  allSupervisorInfo_.init(application->getApplicationContext());
40 
41  if(allSupervisorInfo_.isWizardMode())
42  {
43  __SUP_COUT__ << "Wiz mode detected. So skipping configuration location work for "
44  "supervisor of class '"
45  << supervisorClass_ << "'" << __E__;
46  supervisorContextUID_ = "NO CONTEXT ID IN WIZ MODE";
47  supervisorApplicationUID_ =
48  std::to_string(application->getApplicationDescriptor()->getLocalId());
49  supervisorConfigurationPath_ = "NO APP PATH IN WIZ MODE";
50  return;
51  }
52 
53  __SUP_COUT__ << "Getting configuration specific info for supervisor '"
54  << (allSupervisorInfo_.getSupervisorInfo(application).getName())
55  << "' of class " << supervisorClass_ << "." << __E__;
56 
57  // get configuration specific info for the application supervisor
58 
59  try
60  {
61  CorePropertySupervisorBase::supervisorContextUID_ =
62  theConfigurationManager_->__GET_CONFIG__(XDAQContextTable)
63  ->getContextUID(application->getApplicationContext()
64  ->getContextDescriptor()
65  ->getURL());
66  }
67  catch(...)
68  {
69  __SUP_COUT_ERR__
70  << "XDAQ Supervisor could not access it's configuration through "
71  "the Configuration Manager."
72  << ". The getApplicationContext()->getContextDescriptor()->getURL() = "
73  << application->getApplicationContext()->getContextDescriptor()->getURL()
74  << __E__;
75  throw;
76  }
77 
78  try
79  {
80  CorePropertySupervisorBase::supervisorApplicationUID_ =
81  theConfigurationManager_->__GET_CONFIG__(XDAQContextTable)
82  ->getApplicationUID(
83  application->getApplicationContext()
84  ->getContextDescriptor()
85  ->getURL(),
86  application->getApplicationDescriptor()->getLocalId());
87  }
88  catch(...)
89  {
90  __SUP_COUT_ERR__ << "XDAQ Supervisor could not access it's configuration through "
91  "the Configuration Manager."
92  << " The supervisorContextUID_ = " << supervisorContextUID_
93  << ". The supervisorApplicationUID = "
94  << supervisorApplicationUID_ << __E__;
95  throw;
96  }
97 
98  CorePropertySupervisorBase::supervisorConfigurationPath_ =
99  "/" + CorePropertySupervisorBase::supervisorContextUID_ +
100  "/LinkToApplicationTable/" +
101  CorePropertySupervisorBase::supervisorApplicationUID_ + "/LinkToSupervisorTable";
102 
103  __SUP_COUTV__(CorePropertySupervisorBase::supervisorContextUID_);
104  __SUP_COUTV__(CorePropertySupervisorBase::supervisorApplicationUID_);
105  __SUP_COUTV__(CorePropertySupervisorBase::supervisorConfigurationPath_);
106 
107  CorePropertySupervisorBase::indicateOtsAlive(this);
108 
109 } // end constructor
110 
111 //========================================================================================================================
112 CorePropertySupervisorBase::~CorePropertySupervisorBase(void)
113 {
114  if(theConfigurationManager_)
115  delete theConfigurationManager_;
116 } // end destructor
117 
118 //========================================================================================================================
119 void CorePropertySupervisorBase::indicateOtsAlive(
120  const CorePropertySupervisorBase* properties)
121 {
122  char portStr[100] = "0";
123  std::string hostname = "wiz";
124 
125  // Note: the environment variable getenv("HOSTNAME") fails in multinode ots systems
126  // started through ssh
127 
128  if(properties)
129  {
130  unsigned int port = properties->getContextTreeNode()
131  .getNode(properties->supervisorContextUID_)
132  .getNode("Port")
133  .getValue<unsigned int>();
134  sprintf(portStr, "%u", port);
135 
136  hostname = properties->getContextTreeNode()
137  .getNode(properties->supervisorContextUID_)
138  .getNode("Address")
139  .getValue<std::string>();
140 
141  size_t i = hostname.find("//");
142  if(i != std::string::npos)
143  hostname = hostname.substr(i + 2);
144 
145  __COUTV__(hostname);
146  }
147 
148  // indicate ots is alive (for StartOTS.sh to verify launch was successful)
149  std::string filename = std::string(getenv("OTSDAQ_LOG_DIR")) + "/otsdaq_is_alive-" +
150  hostname + "-" + portStr + ".dat";
151  FILE* fp = fopen(filename.c_str(), "w");
152  if(!fp)
153  {
154  __SS__ << "Failed to open the ots-is-alive file: " << filename << __E__;
155  __SS_THROW__;
156  }
157  fprintf(fp, "%s %s %ld\n", hostname.c_str(), portStr, time(0));
158  fclose(fp);
159 
160  __COUT__ << "Marked alive: " << filename << __E__;
161 }
162 
163 //========================================================================================================================
164 // When overriding, setup default property values here
165 // called by CorePropertySupervisorBase constructor before loading user defined property
166 // values
167 void CorePropertySupervisorBase::setSupervisorPropertyDefaults(void)
168 {
169  // This can be done in the constructor because when you start xdaq it loads the
170  // configuration that can't be changed while running!
171 
172  //__SUP_COUT__ << "Setting up Core Supervisor Base property defaults for supervisor"
173  //<<
174  // "..." << __E__;
175 
176  // set core Supervisor base class defaults
177  CorePropertySupervisorBase::setSupervisorProperty(
178  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold,
179  "*=1");
180  CorePropertySupervisorBase::setSupervisorProperty(
181  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserGroupsAllowed, "");
182  CorePropertySupervisorBase::setSupervisorProperty(
183  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserGroupsDisallowed, "");
184 
185  CorePropertySupervisorBase::setSupervisorProperty(
186  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.CheckUserLockRequestTypes, "");
187  CorePropertySupervisorBase::setSupervisorProperty(
188  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.RequireUserLockRequestTypes,
189  "");
190  CorePropertySupervisorBase::setSupervisorProperty(
191  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes, "");
192  CorePropertySupervisorBase::setSupervisorProperty(
193  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AllowNoLoginRequestTypes, "");
194 
195  CorePropertySupervisorBase::setSupervisorProperty(
196  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NoXmlWhiteSpaceRequestTypes,
197  "");
198  CorePropertySupervisorBase::setSupervisorProperty(
199  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NonXMLRequestTypes, "");
200 
201  // __SUP_COUT__ << "Done setting up Core Supervisor Base property defaults for
202  // supervisor" <<
203  // "..." << __E__;
204 }
205 
206 //========================================================================================================================
207 // extractPermissionsMapFromString
208 // Static function that extract map function to standardize approach
209 // in case needed by supervisors for special permissions handling.
210 // For example, used to serve Desktop Icons.
211 //
212 // permissionsString format is as follows:
213 // <groupName>:<permissionsThreshold> pairs separated by ',' '&' or '|'
214 // for example, to give access admins and pixel team but not calorimeter team:
215 // allUsers:255 | pixelTeam:1 | calorimeterTeam:0
216 //
217 // Use with CorePropertySupervisorBase::doPermissionsGrantAccess to determine
218 // if access is allowed.
219 void CorePropertySupervisorBase::extractPermissionsMapFromString(
220  const std::string& permissionsString,
221  std::map<std::string, WebUsers::permissionLevel_t>& permissionsMap)
222 {
223  permissionsMap.clear();
224  StringMacros::getMapFromString(permissionsString, permissionsMap);
225 }
226 
227 //========================================================================================================================
228 // doPermissionsGrantAccess
229 // Static function that checks permissionLevelsMap against permissionThresholdsMap and
230 // returns true if access requirements are met.
231 //
232 // This is useful in standardizing approach for supervisors in case of
233 // of special permissions handling.
234 // For example, used to serve Desktop Icons.
235 //
236 // permissionLevelsString format is as follows:
237 // <groupName>:<permissionsLevel> pairs separated by ',' '&' or '|'
238 // for example, to be a standard user and an admin on the pixel team and no access to
239 // calorimeter team: allUsers:1 | pixelTeam:255 | calorimeterTeam:0
240 //
241 // permissionThresoldsString format is as follows:
242 // <groupName>:<permissionsThreshold> pairs separated by ',' '&' or '|'
243 // for example, to give access admins and pixel team but not calorimeter team:
244 // allUsers:255 | pixelTeam:1 | calorimeterTeam:0
245 bool CorePropertySupervisorBase::doPermissionsGrantAccess(
246  std::map<std::string, WebUsers::permissionLevel_t>& permissionLevelsMap,
247  std::map<std::string, WebUsers::permissionLevel_t>& permissionThresholdsMap)
248 {
249  // return true if a permission level group name is found with a permission level
250  // greater than or equal to the permission level at a matching group name entry in
251  // the thresholds map.
252 
253  //__COUTV__(StringMacros::mapToString(permissionLevelsMap));
254  //__COUTV__(StringMacros::mapToString(permissionThresholdsMap));
255 
256  for(const auto& permissionLevelGroupPair : permissionLevelsMap)
257  {
258  //__COUTV__(permissionLevelGroupPair.first);
259  //__COUTV__(permissionLevelGroupPair.second);
260 
261  for(const auto& permissionThresholdGroupPair : permissionThresholdsMap)
262  {
263  //__COUTV__(permissionThresholdGroupPair.first);
264  //__COUTV__(permissionThresholdGroupPair.second);
265  if(permissionLevelGroupPair.first == permissionThresholdGroupPair.first &&
266  permissionThresholdGroupPair.second && // not explicitly disallowed
267  permissionLevelGroupPair.second >= permissionThresholdGroupPair.second)
268  return true; // access granted!
269  }
270  }
271  //__COUT__ << "Denied." << __E__;
272 
273  // if here, no access group match found
274  // so denied
275  return false;
276 } // end doPermissionsGrantAccess
277 
278 //========================================================================================================================
279 void CorePropertySupervisorBase::checkSupervisorPropertySetup()
280 {
281  if(propertiesAreSetup_)
282  return;
283 
284  // Immediately mark properties as setup, (prevent infinite loops due to
285  // other launches from within this function, e.g. from getSupervisorProperty)
286  // only redo if Context configuration group changes
287  propertiesAreSetup_ = true;
288 
289  CorePropertySupervisorBase::setSupervisorPropertyDefaults(); // calls base class
290  // version defaults
291 
292  //__SUP_COUT__ << "Setting up supervisor specific property DEFAULTS for supervisor..."
293  //<< __E__;
294  setSupervisorPropertyDefaults(); // calls override version defaults
295  // __SUP_COUT__ << "Done setting up supervisor
296  // specific property DEFAULTS for supervisor" <<
297  // "." << __E__;
298 
299  if(allSupervisorInfo_.isWizardMode())
300  __SUP_COUT__ << "Wiz mode detected. Skipping setup of supervisor properties for "
301  "supervisor of class '"
302  << supervisorClass_ << "'" << __E__;
303  else
304  CorePropertySupervisorBase::loadUserSupervisorProperties(); // loads user
305  // settings from
306  // configuration
307 
308  //__SUP_COUT__ << "Setting up supervisor specific FORCED properties for supervisor..."
309  //<< __E__;
310  forceSupervisorPropertyValues(); // calls override forced values
311  // __SUP_COUT__ << "Done setting up supervisor
312  // specific FORCED properties for supervisor" <<
313  // "." << __E__;
314 
315  CorePropertySupervisorBase::extractPermissionsMapFromString(
316  getSupervisorProperty(
317  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold),
318  propertyStruct_.UserPermissionsThreshold);
319 
320  propertyStruct_.UserGroupsAllowed.clear();
321  StringMacros::getMapFromString(
322  getSupervisorProperty(
323  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserGroupsAllowed),
324  propertyStruct_.UserGroupsAllowed);
325 
326  propertyStruct_.UserGroupsDisallowed.clear();
327  StringMacros::getMapFromString(
328  getSupervisorProperty(
329  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserGroupsDisallowed),
330  propertyStruct_.UserGroupsDisallowed);
331 
332  auto nameIt = SUPERVISOR_PROPERTIES.allSetNames_.begin();
333  auto setIt = propertyStruct_.allSets_.begin();
334  while(nameIt != SUPERVISOR_PROPERTIES.allSetNames_.end() &&
335  setIt != propertyStruct_.allSets_.end())
336  {
337  (*setIt)->clear();
338  StringMacros::getSetFromString(getSupervisorProperty(*(*nameIt)), *(*setIt));
339 
340  ++nameIt;
341  ++setIt;
342  }
343 
344  __SUP_COUT__ << "Final supervisor property settings:" << __E__;
345  for(auto& property : propertyMap_)
346  __SUP_COUT__ << "\t" << property.first << " = " << property.second << __E__;
347 }
348 
349 //========================================================================================================================
350 // getSupervisorTreeNode ~
351 // try to get this Supervisors configuration tree node
352 ConfigurationTree CorePropertySupervisorBase::getSupervisorTreeNode(void) try
353 {
354  if(supervisorContextUID_ == "" || supervisorApplicationUID_ == "")
355  {
356  __SUP_SS__ << "Empty supervisorContextUID_ or supervisorApplicationUID_."
357  << __E__;
358  __SUP_SS_THROW__;
359  }
360  return theConfigurationManager_->getSupervisorNode(supervisorContextUID_,
361  supervisorApplicationUID_);
362 }
363 catch(...)
364 {
365  __SUP_COUT_ERR__
366  << "XDAQ Supervisor could not access it's configuration node through "
367  "theConfigurationManager_ "
368  << "(Did you remember to initialize using CorePropertySupervisorBase::init()?)."
369  << " The supervisorContextUID_ = " << supervisorContextUID_
370  << ". The supervisorApplicationUID = " << supervisorApplicationUID_ << __E__;
371  throw;
372 }
373 
374 //========================================================================================================================
375 // loadUserSupervisorProperties ~
376 // try to get user supervisor properties
377 void CorePropertySupervisorBase::loadUserSupervisorProperties(void)
378 {
379  // __SUP_COUT__ << "Loading user properties for supervisor '" <<
380  // supervisorContextUID_ << "/" << supervisorApplicationUID_ <<
381  // "'..." << __E__;
382 
383  // re-acquire the configuration supervisor node, in case the config has changed
384  auto supervisorNode = CorePropertySupervisorBase::getSupervisorTreeNode();
385 
386  try
387  {
388  auto /*map<name,node>*/ children =
389  supervisorNode.getNode("LinkToPropertyTable").getChildren();
390 
391  for(auto& child : children)
392  {
393  if(child.second.getNode("Status").getValue<bool>() == false)
394  continue; // skip OFF properties
395 
396  auto propertyName = child.second.getNode("PropertyName").getValue();
397  setSupervisorProperty(
398  propertyName,
399  child.second.getNode("PropertyValue").getValue<std::string>());
400  }
401  }
402  catch(...)
403  {
404  __SUP_COUT__ << "No user supervisor property settings found in the configuration "
405  "tree, going with the defaults."
406  << __E__;
407  }
408 
409  // __SUP_COUT__ << "Done loading user properties for supervisor '" <<
410  // supervisorContextUID_ << "/" << supervisorApplicationUID_ <<
411  // "'" << __E__;
412 }
413 
414 //========================================================================================================================
415 void CorePropertySupervisorBase::setSupervisorProperty(const std::string& propertyName,
416  const std::string& propertyValue)
417 {
418  propertyMap_[propertyName] = propertyValue;
419  // __SUP_COUT__ << "Set propertyMap_[" << propertyName <<
420  // "] = " << propertyMap_[propertyName] << __E__;
421 }
422 
423 //========================================================================================================================
424 void CorePropertySupervisorBase::addSupervisorProperty(const std::string& propertyName,
425  const std::string& propertyValue)
426 {
427  propertyMap_[propertyName] =
428  propertyValue + " | " + getSupervisorProperty(propertyName);
429  // __SUP_COUT__ << "Set propertyMap_[" << propertyName <<
430  // "] = " << propertyMap_[propertyName] << __E__;
431 }
432 
433 //========================================================================================================================
434 // getSupervisorProperty
435 // string version of template function
436 std::string CorePropertySupervisorBase::getSupervisorProperty(
437  const std::string& propertyName)
438 {
439  // check if need to setup properties
440  checkSupervisorPropertySetup();
441 
442  auto it = propertyMap_.find(propertyName);
443  if(it == propertyMap_.end())
444  {
445  __SUP_SS__ << "Could not find property named " << propertyName << __E__;
446  __SS_THROW__; //__SUP_SS_THROW__;
447  }
448  return StringMacros::validateValueForDefaultStringDataType(it->second);
449 }
450 
451 //========================================================================================================================
452 // getSupervisorPropertyUserPermissionsThreshold
453 // returns the threshold based on the requestType
454 WebUsers::permissionLevel_t
455 CorePropertySupervisorBase::getSupervisorPropertyUserPermissionsThreshold(
456  const std::string& requestType)
457 {
458  // check if need to setup properties
459  checkSupervisorPropertySetup();
460 
461  return StringMacros::getWildCardMatchFromMap(
462  requestType, propertyStruct_.UserPermissionsThreshold);
463 
464  // auto it = propertyStruct_.UserPermissionsThreshold.find(requestType);
465  // if(it == propertyStruct_.UserPermissionsThreshold.end())
466  // {
467  // __SUP_SS__ << "Could not find requestType named " << requestType << " in
468  // UserPermissionsThreshold map." << __E__;
469  // __SS_THROW__; //__SUP_SS_THROW__;
470  // }
471  // return it->second;
472 }
473 
474 //========================================================================================================================
475 // getRequestUserInfo ~
476 // extract user info for request based on property configuration
477 void CorePropertySupervisorBase::getRequestUserInfo(WebUsers::RequestUserInfo& userInfo)
478 {
479  checkSupervisorPropertySetup();
480 
481  //__SUP_COUT__ << "userInfo.requestType_ " << userInfo.requestType_ << " files: " <<
482  // cgiIn.getFiles().size() << __E__;
483 
484  userInfo.automatedCommand_ = StringMacros::inWildCardSet(
485  userInfo.requestType_,
486  propertyStruct_.AutomatedRequestTypes); // automatic commands should not refresh
487  // cookie code.. only user initiated
488  // commands should!
489  userInfo.NonXMLRequestType_ = StringMacros::inWildCardSet(
490  userInfo.requestType_, propertyStruct_.NonXMLRequestTypes); // non-xml request
491  // types just return
492  // the request return
493  // string to client
494  userInfo.NoXmlWhiteSpace_ = StringMacros::inWildCardSet(
495  userInfo.requestType_, propertyStruct_.NoXmlWhiteSpaceRequestTypes);
496 
497  //**** start LOGIN GATEWAY CODE ***//
498  // check cookieCode, sequence, userWithLock, and permissions access all in one shot!
499  {
500  userInfo.checkLock_ = StringMacros::inWildCardSet(
501  userInfo.requestType_, propertyStruct_.CheckUserLockRequestTypes);
502  userInfo.requireLock_ = StringMacros::inWildCardSet(
503  userInfo.requestType_, propertyStruct_.RequireUserLockRequestTypes);
504  userInfo.allowNoUser_ = StringMacros::inWildCardSet(
505  userInfo.requestType_, propertyStruct_.AllowNoLoginRequestTypes);
506 
507  userInfo.permissionsThreshold_ = -1; // default to max
508  try
509  {
510  userInfo.permissionsThreshold_ =
511  CorePropertySupervisorBase::getSupervisorPropertyUserPermissionsThreshold(
512  userInfo.requestType_);
513  }
514  catch(std::runtime_error& e)
515  {
516  if(!userInfo.automatedCommand_)
517  __SUP_COUT__ << "No explicit permissions threshold for request '"
518  << userInfo.requestType_
519  << "'... Defaulting to max threshold = "
520  << (unsigned int)userInfo.permissionsThreshold_ << __E__;
521  }
522 
523  // __COUTV__(userInfo.requestType_);
524  // __COUTV__(userInfo.checkLock_);
525  // __COUTV__(userInfo.requireLock_);
526  // __COUTV__(userInfo.allowNoUser_);
527  // __COUTV__((unsigned int)userInfo.permissionsThreshold_);
528 
529  try
530  {
531  StringMacros::getSetFromString(
532  StringMacros::getWildCardMatchFromMap(userInfo.requestType_,
533  propertyStruct_.UserGroupsAllowed),
534  userInfo.groupsAllowed_);
535  }
536  catch(std::runtime_error& e)
537  {
538  userInfo.groupsAllowed_.clear();
539 
540  // if(!userInfo.automatedCommand_)
541  // __SUP_COUT__ << "No explicit groups allowed for request '" <<
542  // userInfo.requestType_ << "'... Defaulting to empty groups
543  // allowed. " << __E__;
544  }
545  try
546  {
547  StringMacros::getSetFromString(
548  StringMacros::getWildCardMatchFromMap(
549  userInfo.requestType_, propertyStruct_.UserGroupsDisallowed),
550  userInfo.groupsDisallowed_);
551  }
552  catch(std::runtime_error& e)
553  {
554  userInfo.groupsDisallowed_.clear();
555 
556  // if(!userInfo.automatedCommand_)
557  // __SUP_COUT__ << "No explicit groups disallowed for request '"
558  //<<
559  // userInfo.requestType_ << "'... Defaulting to empty groups
560  // disallowed. " << __E__;
561  }
562  } //**** end LOGIN GATEWAY CODE ***//
563 
564  // completed user info, for the request type, is returned to caller
565 }
void init(xdaq::ApplicationContext *applicationContext)