1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <IceUtil/DisableWarnings.h>
6 #include <IceUtil/FileUtil.h>
7 #include <Ice/Ice.h>
8 #include <IceGrid/ServerI.h>
9 #include <IceGrid/TraceLevels.h>
10 #include <IceGrid/Activator.h>
11 #include <IceGrid/NodeI.h>
12 #include <IceGrid/Util.h>
13 #include <IceGrid/ServerAdapterI.h>
14 #include <IceGrid/DescriptorHelper.h>
15
16 #include <IcePatch2Lib/Util.h>
17 #include <IceUtil/FileUtil.h>
18
19 #include <sys/types.h>
20 #include <fstream>
21
22 #ifdef _WIN32
23 # include <direct.h>
24 # include <signal.h>
25 #else
26 # include <sys/wait.h>
27 # include <pwd.h> // for getpwnam
28 # include <signal.h>
29 # include <unistd.h>
30 # include <dirent.h>
31 #endif
32
33 using namespace std;
34 using namespace IceGrid;
35
36 namespace IceGrid
37 {
38
39 #ifndef _WIN32
40 void
chownRecursive(const string & path,uid_t uid,gid_t gid)41 chownRecursive(const string& path, uid_t uid, gid_t gid)
42 {
43 vector<vector<Ice::Byte> > namelist;
44 DIR* d;
45 if((d = opendir(path.c_str())) == 0)
46 {
47 throw runtime_error("cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString());
48 }
49
50 struct dirent* entry;
51 while((entry = readdir(d)) != 0)
52 {
53 size_t index = namelist.size();
54 namelist.resize(index + 1);
55
56 size_t entrysize = sizeof(struct dirent) - sizeof(entry->d_name) + strlen(entry->d_name) + 1;
57 namelist[index].resize(entrysize);
58
59 memcpy(&namelist[index][0], entry, entrysize);
60 }
61
62 if(closedir(d))
63 {
64 throw runtime_error("cannot read directory `" + path + "':\n" + IceUtilInternal::lastErrorToString());
65 }
66
67 for(size_t i = 0; i < namelist.size(); ++i)
68 {
69 string name = reinterpret_cast<struct dirent*>(&namelist[i][0])->d_name;
70 assert(!name.empty());
71
72 if(name == ".")
73 {
74 if(chown(path.c_str(), uid, gid) != 0)
75 {
76 throw runtime_error("can't change permissions on `" + name + "':\n" + IceUtilInternal::lastErrorToString());
77 }
78 }
79 else if(name != "..")
80 {
81 name = path + "/" + name;
82
83 IceUtilInternal::structstat buf;
84 if(IceUtilInternal::stat(name, &buf) == -1)
85 {
86 throw runtime_error("cannot stat `" + name + "':\n" + IceUtilInternal::lastErrorToString());
87 }
88
89 if(S_ISDIR(buf.st_mode))
90 {
91 chownRecursive(name, uid, gid);
92 }
93 else
94 {
95 if(chown(name.c_str(), uid, gid) != 0)
96 {
97 throw runtime_error("can't change permissions on `" + name + "':\n" + IceUtilInternal::lastErrorToString());
98 }
99 }
100 }
101 }
102 }
103 #endif
104
105 static bool
descriptorUpdated(const InternalServerDescriptorPtr & lhs,const InternalServerDescriptorPtr & rhs,bool noProps=false)106 descriptorUpdated(const InternalServerDescriptorPtr& lhs, const InternalServerDescriptorPtr& rhs, bool noProps = false)
107 {
108 if(lhs->uuid == rhs->uuid && lhs->revision == rhs->revision)
109 {
110 return false;
111 }
112
113 if(lhs->id != rhs->id ||
114 lhs->application != rhs->application ||
115 lhs->uuid != rhs->uuid ||
116 lhs->sessionId != rhs->sessionId ||
117 lhs->exe != rhs->exe ||
118 lhs->pwd != rhs->pwd ||
119 lhs->user != rhs->user ||
120 lhs->activation != rhs->activation ||
121 lhs->activationTimeout != rhs->activationTimeout ||
122 lhs->deactivationTimeout != rhs->deactivationTimeout ||
123 lhs->applicationDistrib != rhs->applicationDistrib ||
124 lhs->processRegistered != rhs->processRegistered ||
125 lhs->options != rhs->options ||
126 lhs->envs != rhs->envs ||
127 lhs->logs != rhs->logs)
128 {
129 return true;
130 }
131
132 if((!lhs->distrib && rhs->distrib) || (lhs->distrib && !rhs->distrib))
133 {
134 return true;
135 }
136 else if(lhs->distrib && rhs->distrib)
137 {
138 if(lhs->distrib->icepatch != rhs->distrib->icepatch ||
139 lhs->distrib->directories != rhs->distrib->directories)
140 {
141 return true;
142 }
143 }
144
145 if(lhs->adapters.size() != rhs->adapters.size())
146 {
147 return true;
148 }
149 else
150 {
151 InternalAdapterDescriptorSeq::const_iterator q = rhs->adapters.begin();
152 for(InternalAdapterDescriptorSeq::const_iterator p = lhs->adapters.begin(); p != lhs->adapters.end(); ++p, ++q)
153 {
154 if((*p)->id != (*q)->id || (*p)->serverLifetime != (*q)->serverLifetime)
155 {
156 return true;
157 }
158 }
159 }
160
161 if(lhs->dbEnvs.size() != rhs->dbEnvs.size())
162 {
163 return true;
164 }
165 else
166 {
167 InternalDbEnvDescriptorSeq::const_iterator q = rhs->dbEnvs.begin();
168 for(InternalDbEnvDescriptorSeq::const_iterator p = lhs->dbEnvs.begin(); p != lhs->dbEnvs.end(); ++p, ++q)
169 {
170 if((*p)->name != (*q)->name || (*p)->properties != (*q)->properties)
171 {
172 return true;
173 }
174 }
175 }
176
177 if(!noProps && lhs->properties != rhs->properties)
178 {
179 return true;
180 }
181
182 return false;
183 }
184
185 Ice::PropertyDict
toPropertyDict(const PropertyDescriptorSeq & seq)186 toPropertyDict(const PropertyDescriptorSeq& seq)
187 {
188 Ice::PropertyDict props;
189 for(PropertyDescriptorSeq::const_iterator q = seq.begin(); q != seq.end(); ++q)
190 {
191 if(q->value.empty() && q->name.find('#') == 0)
192 {
193 continue; // Ignore comments.
194 }
195
196 if(q->value.empty())
197 {
198 props.erase(q->name);
199 }
200 else
201 {
202 props[q->name] = q->value;
203 }
204 }
205 return props;
206 }
207
208 class CommandTimeoutTimerTask : public IceUtil::TimerTask
209 {
210 public:
211
CommandTimeoutTimerTask(const TimedServerCommandPtr & command)212 CommandTimeoutTimerTask(const TimedServerCommandPtr& command) : _command(command)
213 {
214 }
215
runTimerTask()216 virtual void runTimerTask()
217 {
218 _command->timeout();
219 }
220
221 private:
222
223 const TimedServerCommandPtr _command;
224 };
225
226 class DelayedStart : public IceUtil::TimerTask
227 {
228 public:
229
DelayedStart(const ServerIPtr & server,const TraceLevelsPtr & traceLevels)230 DelayedStart(const ServerIPtr& server, const TraceLevelsPtr& traceLevels) :
231 _server(server),
232 _traceLevels(traceLevels)
233 {
234 }
235
runTimerTask()236 virtual void runTimerTask()
237 {
238 try
239 {
240 _server->start(ServerI::Always);
241 }
242 catch(const ServerStartException& ex)
243 {
244 Ice::Error out(_traceLevels->logger);
245 out << "couldn't reactivate server `" << _server->getId()
246 << "' with `always' activation mode after failure:\n"
247 << ex.reason;
248 }
249 catch(const Ice::ObjectNotExistException&)
250 {
251 }
252 }
253
254 private:
255
256 const ServerIPtr _server;
257 const TraceLevelsPtr _traceLevels;
258 };
259
260 class ResetPropertiesCB : public IceUtil::Shared
261 {
262 public:
263
ResetPropertiesCB(const ServerIPtr & server,const Ice::ObjectPrx admin,const InternalServerDescriptorPtr & desc,const InternalServerDescriptorPtr & old,const TraceLevelsPtr & traceLevels)264 ResetPropertiesCB(const ServerIPtr& server,
265 const Ice::ObjectPrx admin,
266 const InternalServerDescriptorPtr& desc,
267 const InternalServerDescriptorPtr& old,
268 const TraceLevelsPtr& traceLevels) :
269 _server(server),
270 _admin(admin),
271 _desc(desc),
272 _traceLevels(traceLevels),
273 _properties(server->getProperties(desc)),
274 _oldProperties(server->getProperties(old)),
275 _p(_properties.begin())
276 {
277 }
278
279 void
execute()280 execute()
281 {
282 assert(_p != _properties.end());
283 next();
284 }
285
286 private:
287
288 void
next()289 next()
290 {
291 while(_p != _properties.end() && _p->second == _oldProperties[_p->first])
292 {
293 ++_p;
294 }
295 if(_p == _properties.end())
296 {
297 _server->updateRuntimePropertiesCallback(_desc);
298 return;
299 }
300
301 Ice::PropertyDict oldProps = toPropertyDict(_oldProperties[_p->first]);
302 Ice::PropertyDict props = toPropertyDict(_p->second);
303 for(Ice::PropertyDict::const_iterator q = oldProps.begin(); q != oldProps.end(); ++q)
304 {
305 if(props.find(q->first) == props.end())
306 {
307 props[q->first] = "";
308 }
309 }
310
311 string facet;
312 if(_p->first == "config")
313 {
314 facet = "Properties";
315 if(_traceLevels->server > 1)
316 {
317 const string id = _server->getId();
318 Ice::Trace out(_traceLevels->logger, _traceLevels->serverCat);
319 out << "updating runtime properties for server `" << id << "'";
320 }
321 }
322 else
323 {
324 assert(_p->first.find("config_") == 0);
325 const string service = _p->first.substr(7);
326 if(getPropertyAsInt(_properties["config"], "IceBox.UseSharedCommunicator." + service) > 0)
327 {
328 facet = "IceBox.SharedCommunicator.Properties";
329 }
330 else
331 {
332 facet = "IceBox.Service." + service + ".Properties";
333 }
334 if(_traceLevels->server > 1)
335 {
336 const string id = _server->getId();
337 Ice::Trace out(_traceLevels->logger, _traceLevels->serverCat);
338 out << "updating runtime properties for service `" << service << "' from server `" + id + "'";
339 }
340 }
341
342 //
343 // Increment the iterator *before* invoking setProperties_async to avoid a
344 // race condition.
345 //
346 ++_p;
347
348 Ice::PropertiesAdminPrx p = Ice::PropertiesAdminPrx::uncheckedCast(_admin, facet);
349 p->begin_setProperties(props, Ice::newCallback_PropertiesAdmin_setProperties(this,
350 &ResetPropertiesCB::next,
351 &ResetPropertiesCB::exception));
352 }
353
354 void
exception(const Ice::Exception & ex)355 exception(const Ice::Exception& ex)
356 {
357 _server->updateRuntimePropertiesCallback(ex, _desc);
358 }
359
360 const ServerIPtr _server;
361 const Ice::ObjectPrx _admin;
362 const InternalServerDescriptorPtr _desc;
363 const TraceLevelsPtr _traceLevels;
364 PropertyDescriptorSeqDict _properties;
365 PropertyDescriptorSeqDict _oldProperties;
366 PropertyDescriptorSeqDict::const_iterator _p;
367 };
368 typedef IceUtil::Handle<ResetPropertiesCB> ResetPropertiesCBPtr;
369
370 struct EnvironmentEval : std::unary_function<string, string>
371 {
372
373 string
operator ()IceGrid::EnvironmentEval374 operator()(const std::string& value)
375 {
376 string::size_type assignment = value.find("=");
377 if(assignment == string::npos || assignment >= value.size() - 1)
378 {
379 return value;
380 }
381
382 string v = value.substr(assignment + 1);
383 assert(v.size());
384 string::size_type beg = 0;
385 string::size_type end;
386 #ifdef _WIN32
387 vector<wchar_t> buf;
388 buf.resize(32767);
389 while((beg = v.find("%", beg)) != string::npos && beg < v.size() - 1)
390 {
391 end = v.find("%", beg + 1);
392 if(end == string::npos)
393 {
394 break;
395 }
396 string variable = v.substr(beg + 1, end - beg - 1);
397 DWORD ret = GetEnvironmentVariableW(Ice::stringToWstring(variable).c_str(), &buf[0],
398 static_cast<DWORD>(buf.size()));
399 string valstr = (ret > 0 && ret < buf.size()) ? Ice::wstringToString(&buf[0]) : string("");
400 v.replace(beg, end - beg + 1, valstr);
401 beg += valstr.size();
402 }
403 #else
404 while((beg = v.find("$", beg)) != string::npos && beg < v.size() - 1)
405 {
406 string variable;
407 if(v[beg + 1] == '{')
408 {
409 end = v.find("}");
410 if(end == string::npos)
411 {
412 break;
413 }
414 variable = v.substr(beg + 2, end - beg - 2);
415 }
416 else
417 {
418 end = beg + 1;
419 while((isalnum(static_cast<unsigned char>(v[end])) || v[end] == '_') && end < v.size())
420 {
421 ++end;
422 }
423 variable = v.substr(beg + 1, end - beg - 1);
424 --end;
425 }
426
427 char* val = getenv(variable.c_str());
428 string valstr = val ? string(val) : "";
429 v.replace(beg, end - beg + 1, valstr);
430 beg += valstr.size();
431 }
432 #endif
433 return value.substr(0, assignment) + "=" + v;
434 }
435
436 };
437
438 }
439
ServerCommand(const ServerIPtr & server)440 ServerCommand::ServerCommand(const ServerIPtr& server) : _server(server)
441 {
442 }
443
~ServerCommand()444 ServerCommand::~ServerCommand()
445 {
446 }
447
TimedServerCommand(const ServerIPtr & server,const IceUtil::TimerPtr & timer,int timeout)448 TimedServerCommand::TimedServerCommand(const ServerIPtr& server, const IceUtil::TimerPtr& timer, int timeout) :
449 ServerCommand(server), _timer(timer), _timeout(timeout)
450 {
451 }
452
453 void
startTimer()454 TimedServerCommand::startTimer()
455 {
456 _timerTask = new CommandTimeoutTimerTask(this);
457 try
458 {
459 _timer->schedule(_timerTask, IceUtil::Time::seconds(_timeout));
460 }
461 catch(const IceUtil::Exception&)
462 {
463 // Ignore, timer is destroyed because node is shutting down.
464 }
465 }
466
467 void
stopTimer()468 TimedServerCommand::stopTimer()
469 {
470 if(_timerTask)
471 {
472 _timer->cancel(_timerTask);
473 _timerTask = 0;
474 }
475 }
476
LoadCommand(const ServerIPtr & server,const InternalServerDescriptorPtr & runtime,const TraceLevelsPtr & traceLevels)477 LoadCommand::LoadCommand(const ServerIPtr& server,
478 const InternalServerDescriptorPtr& runtime,
479 const TraceLevelsPtr& traceLevels) :
480 ServerCommand(server), _runtime(runtime), _updating(false), _traceLevels(traceLevels)
481 {
482 }
483
484 bool
canExecute(ServerI::InternalServerState state)485 LoadCommand::canExecute(ServerI::InternalServerState state)
486 {
487 return state == ServerI::Inactive;
488 }
489
490 ServerI::InternalServerState
nextState()491 LoadCommand::nextState()
492 {
493 return ServerI::Loading;
494 }
495
496 void
execute()497 LoadCommand::execute()
498 {
499 _server->update();
500 }
501
502 void
setUpdate(const InternalServerDescriptorPtr & descriptor,bool clearDir)503 LoadCommand::setUpdate(const InternalServerDescriptorPtr& descriptor, bool clearDir)
504 {
505 _clearDir = clearDir;
506 _desc = descriptor;
507 }
508
509 InternalServerDescriptorPtr
getInternalServerDescriptor() const510 LoadCommand::getInternalServerDescriptor() const
511 {
512 return _desc;
513 }
514
515 bool
clearDir() const516 LoadCommand::clearDir() const
517 {
518 return _clearDir;
519 }
520
521 void
addCallback(const AMD_Node_loadServerPtr & amdCB)522 LoadCommand::addCallback(const AMD_Node_loadServerPtr& amdCB)
523 {
524 _loadCB.push_back(amdCB);
525 }
526
527 void
startRuntimePropertiesUpdate(const Ice::ObjectPrx & process)528 LoadCommand::startRuntimePropertiesUpdate(const Ice::ObjectPrx& process)
529 {
530 if(_updating)
531 {
532 return;
533 }
534 assert(_desc != _runtime);
535 _updating = true;
536
537 ResetPropertiesCBPtr cb = new ResetPropertiesCB(_server, process, _desc, _runtime, _traceLevels);
538 cb->execute();
539 }
540
541 bool
finishRuntimePropertiesUpdate(const InternalServerDescriptorPtr & runtime,const Ice::ObjectPrx & process)542 LoadCommand::finishRuntimePropertiesUpdate(const InternalServerDescriptorPtr& runtime, const Ice::ObjectPrx& process)
543 {
544 _updating = false;
545 _runtime = runtime; // The new runtime server descriptor.
546
547 if(_traceLevels->server > 0)
548 {
549 Ice::Trace out(_traceLevels->logger, _traceLevels->serverCat);
550 out << "updated runtime properties for server `" << _server->getId() << "'";
551 }
552
553 if(_desc != _runtime)
554 {
555 startRuntimePropertiesUpdate(process);
556 return false;
557 }
558 else
559 {
560 return true;
561 }
562 }
563
564 void
failed(const Ice::Exception & ex)565 LoadCommand::failed(const Ice::Exception& ex)
566 {
567 for(vector<AMD_Node_loadServerPtr>::const_iterator p = _loadCB.begin(); p != _loadCB.end(); ++p)
568 {
569 (*p)->ice_exception(ex);
570 }
571 _loadCB.clear();
572 }
573
574 void
finished(const ServerPrx & proxy,const AdapterPrxDict & adapters,int at,int dt)575 LoadCommand::finished(const ServerPrx& proxy, const AdapterPrxDict& adapters, int at, int dt)
576 {
577 for(vector<AMD_Node_loadServerPtr>::const_iterator p = _loadCB.begin(); p != _loadCB.end(); ++p)
578 {
579 (*p)->ice_response(proxy, adapters, at, dt);
580 }
581 _loadCB.clear();
582 }
583
DestroyCommand(const ServerIPtr & server,bool loadFailure,bool clearDir)584 DestroyCommand::DestroyCommand(const ServerIPtr& server, bool loadFailure, bool clearDir) :
585 ServerCommand(server),
586 _loadFailure(loadFailure),
587 _clearDir(clearDir)
588 {
589 }
590
591 bool
canExecute(ServerI::InternalServerState state)592 DestroyCommand::canExecute(ServerI::InternalServerState state)
593 {
594 return state == ServerI::Inactive;
595 }
596
597 ServerI::InternalServerState
nextState()598 DestroyCommand::nextState()
599 {
600 return ServerI::Destroying;
601 }
602
603 void
execute()604 DestroyCommand::execute()
605 {
606 _server->destroy();
607 }
608
609 void
addCallback(const AMD_Node_destroyServerPtr & amdCB)610 DestroyCommand::addCallback(const AMD_Node_destroyServerPtr& amdCB)
611 {
612 _destroyCB.push_back(amdCB);
613 }
614
615 void
finished()616 DestroyCommand::finished()
617 {
618 for(vector<AMD_Node_destroyServerPtr>::const_iterator p = _destroyCB.begin(); p != _destroyCB.end(); ++p)
619 {
620 (*p)->ice_response();
621 }
622 }
623
624 bool
loadFailure() const625 DestroyCommand::loadFailure() const
626 {
627 return _loadFailure;
628 }
629
630 bool
clearDir() const631 DestroyCommand::clearDir() const
632 {
633 return _clearDir;
634 }
635
PatchCommand(const ServerIPtr & server)636 PatchCommand::PatchCommand(const ServerIPtr& server) :
637 ServerCommand(server),
638 _notified(false),
639 _destroyed(false)
640 {
641 }
642
643 bool
canExecute(ServerI::InternalServerState state)644 PatchCommand::canExecute(ServerI::InternalServerState state)
645 {
646 return state == ServerI::Inactive;
647 }
648
649 ServerI::InternalServerState
nextState()650 PatchCommand::nextState()
651 {
652 return ServerI::Patching;
653 }
654
655 void
execute()656 PatchCommand::execute()
657 {
658 Lock sync(*this);
659 _notified = true;
660 notifyAll();
661 }
662
663 bool
waitForPatch()664 PatchCommand::waitForPatch()
665 {
666 Lock sync(*this);
667 while(!_notified && !_destroyed)
668 {
669 wait();
670 }
671 return _destroyed;
672 }
673
674 void
destroyed()675 PatchCommand::destroyed()
676 {
677 Lock sync(*this);
678 _destroyed = true;
679 notifyAll();
680 }
681
682 void
finished()683 PatchCommand::finished()
684 {
685 }
686
StartCommand(const ServerIPtr & server,const IceUtil::TimerPtr & timer,int timeout)687 StartCommand::StartCommand(const ServerIPtr& server, const IceUtil::TimerPtr& timer, int timeout) :
688 TimedServerCommand(server, timer, timeout)
689 {
690 }
691
692 bool
canExecute(ServerI::InternalServerState state)693 StartCommand::canExecute(ServerI::InternalServerState state)
694 {
695 return state == ServerI::Inactive;
696 }
697
698 ServerI::InternalServerState
nextState()699 StartCommand::nextState()
700 {
701 startTimer();
702 return ServerI::Activating;
703 }
704
705 void
execute()706 StartCommand::execute()
707 {
708 _server->activate();
709 }
710
711 void
timeout()712 StartCommand::timeout()
713 {
714 _server->activationTimedOut();
715 }
716
717 void
addCallback(const AMD_Server_startPtr & amdCB)718 StartCommand::addCallback(const AMD_Server_startPtr& amdCB)
719 {
720 _startCB.push_back(amdCB);
721 }
722
723 void
failed(const string & reason)724 StartCommand::failed(const string& reason)
725 {
726 stopTimer();
727 ServerStartException ex(_server->getId(), reason);
728 for(vector<AMD_Server_startPtr>::const_iterator p = _startCB.begin(); p != _startCB.end(); ++p)
729 {
730 (*p)->ice_exception(ex);
731 }
732 _startCB.clear();
733 }
734
735 void
finished()736 StartCommand::finished()
737 {
738 stopTimer();
739 for(vector<AMD_Server_startPtr>::const_iterator p = _startCB.begin(); p != _startCB.end(); ++p)
740 {
741 (*p)->ice_response();
742 }
743 _startCB.clear();
744 }
745
StopCommand(const ServerIPtr & server,const IceUtil::TimerPtr & timer,int timeout,bool deactivate)746 StopCommand::StopCommand(const ServerIPtr& server, const IceUtil::TimerPtr& timer, int timeout, bool deactivate)
747 : TimedServerCommand(server, timer, timeout), _deactivate(deactivate)
748 {
749 }
750
751 bool
isStopped(ServerI::InternalServerState state)752 StopCommand::isStopped(ServerI::InternalServerState state)
753 {
754 return state == ServerI::Inactive || state == ServerI::Patching || state == ServerI::Loading ||
755 state >= ServerI::Destroying;
756 }
757
758 bool
canExecute(ServerI::InternalServerState state)759 StopCommand::canExecute(ServerI::InternalServerState state)
760 {
761 return state == ServerI::WaitForActivation || state == ServerI::ActivationTimeout || state == ServerI::Active;
762 }
763
764 ServerI::InternalServerState
nextState()765 StopCommand::nextState()
766 {
767 startTimer();
768 return ServerI::Deactivating;
769 }
770
771 void
execute()772 StopCommand::execute()
773 {
774 if(_deactivate)
775 {
776 _server->deactivate();
777 }
778 }
779
780 void
timeout()781 StopCommand::timeout()
782 {
783 _server->kill();
784 }
785
786 void
addCallback(const AMD_Server_stopPtr & amdCB)787 StopCommand::addCallback(const AMD_Server_stopPtr& amdCB)
788 {
789 _stopCB.push_back(amdCB);
790 }
791
792 void
failed(const string & reason)793 StopCommand::failed(const string& reason)
794 {
795 stopTimer();
796 ServerStopException ex(_server->getId(), reason);
797 for(vector<AMD_Server_stopPtr>::const_iterator p = _stopCB.begin(); p != _stopCB.end(); ++p)
798 {
799 (*p)->ice_exception(ex);
800 }
801 _stopCB.clear();
802 }
803
804 void
finished()805 StopCommand::finished()
806 {
807 stopTimer();
808 for(vector<AMD_Server_stopPtr>::const_iterator p = _stopCB.begin(); p != _stopCB.end(); ++p)
809 {
810 (*p)->ice_response();
811 }
812 _stopCB.clear();
813 }
814
ServerI(const NodeIPtr & node,const ServerPrx & proxy,const string & serversDir,const string & id,int wt)815 ServerI::ServerI(const NodeIPtr& node, const ServerPrx& proxy, const string& serversDir, const string& id, int wt) :
816 _node(node),
817 _this(proxy),
818 _id(id),
819 _waitTime(wt),
820 _serverDir(serversDir + "/" + id),
821 _disableOnFailure(0),
822 _state(ServerI::Inactive),
823 _activation(ServerI::Disabled),
824 _failureTime(IceUtil::Time::now(IceUtil::Time::Monotonic)), // Ensure that _activation is init. in updateImpl().
825 _pid(0)
826 {
827 assert(_node->getActivator());
828 const_cast<int&>(_disableOnFailure) =
829 _node->getCommunicator()->getProperties()->getPropertyAsIntWithDefault("IceGrid.Node.DisableOnFailure", 0);
830 }
831
~ServerI()832 ServerI::~ServerI()
833 {
834 }
835
836 void
waitForApplicationUpdateCompleted(const Ice::AsyncResultPtr &)837 ServerI::waitForApplicationUpdateCompleted(const Ice::AsyncResultPtr&)
838 {
839 activate();
840 }
841
842 void
start_async(const AMD_Server_startPtr & amdCB,const Ice::Current &)843 ServerI::start_async(const AMD_Server_startPtr& amdCB, const Ice::Current&)
844 {
845 start(Manual, amdCB);
846 }
847
848 void
stop_async(const AMD_Server_stopPtr & amdCB,const Ice::Current &)849 ServerI::stop_async(const AMD_Server_stopPtr& amdCB, const Ice::Current&)
850 {
851 ServerCommandPtr command;
852 {
853 Lock sync(*this);
854 checkDestroyed();
855
856 if(StopCommand::isStopped(_state))
857 {
858 throw ServerStopException(_id, "The server is already inactive.");
859 }
860 else if(_state == Destroying)
861 {
862 throw ServerStopException(_id, "The server is being destroyed.");
863 }
864
865 if(!_stop)
866 {
867 _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout);
868 }
869 if(amdCB)
870 {
871 _stop->addCallback(amdCB);
872 }
873 command = nextCommand();
874 }
875 if(command)
876 {
877 command->execute();
878 }
879 }
880
881 void
sendSignal(const string & signal,const Ice::Current &)882 ServerI::sendSignal(const string& signal, const Ice::Current&)
883 {
884 _node->getActivator()->sendSignal(_id, signal);
885 }
886
887 void
writeMessage(const string & message,Ice::Int fd,const Ice::Current &)888 ServerI::writeMessage(const string& message, Ice::Int fd, const Ice::Current&)
889 {
890 Lock sync(*this);
891 checkDestroyed();
892 if(_process != 0)
893 {
894 try
895 {
896 _process->writeMessage(message, fd);
897 }
898 catch(const Ice::LocalException&)
899 {
900 }
901 }
902 }
903
904 ServerState
getState(const Ice::Current &) const905 ServerI::getState(const Ice::Current&) const
906 {
907 Lock sync(*this);
908 checkDestroyed();
909 return toServerState(_state);
910 }
911
912 Ice::Int
getPid(const Ice::Current &) const913 ServerI::getPid(const Ice::Current&) const
914 {
915 return _node->getActivator()->getServerPid(_id);
916 }
917
918 Ice::ObjectPrx
getProcess() const919 ServerI::getProcess() const
920 {
921 Lock sync(*this);
922
923 if(_process == 0 || _state <= Inactive || _state >= Deactivating)
924 {
925 return 0;
926 }
927 else
928 {
929 return _process;
930 }
931 }
932
933 void
setEnabled(bool enabled,const::Ice::Current &)934 ServerI::setEnabled(bool enabled, const ::Ice::Current&)
935 {
936 bool activate = false;
937 ServerAdapterDict adpts;
938 {
939 Lock sync(*this);
940 checkDestroyed();
941 assert(_desc);
942
943 if(enabled && _activation == Disabled)
944 {
945 _failureTime = IceUtil::Time();
946 _activation = toServerActivation(_desc->activation);
947 activate = _state == Inactive && _activation == Always;
948 }
949 else if(!enabled && (_activation != Disabled || _failureTime != IceUtil::Time()))
950 {
951 _failureTime = IceUtil::Time();
952 _activation = Disabled;
953 if(_timerTask)
954 {
955 _node->getTimer()->cancel(_timerTask);
956 _timerTask = 0;
957 }
958 }
959 else
960 {
961 return; // Nothing to change!
962 }
963
964 adpts = _adapters;
965 _node->observerUpdateServer(getDynamicInfo());
966 }
967
968 for(ServerAdapterDict::iterator r = adpts.begin(); r != adpts.end(); ++r)
969 {
970 r->second->updateEnabled();
971 }
972
973 if(activate)
974 {
975 try
976 {
977 start(Always);
978 }
979 catch(const ServerStartException& ex)
980 {
981 Ice::Error out(_node->getTraceLevels()->logger);
982 out << "couldn't reactivate server `" << _id << "' with `always' activation mode:\n"
983 << ex.reason;
984 }
985 catch(const Ice::ObjectNotExistException&)
986 {
987 }
988 }
989 }
990
991 bool
isEnabled(const::Ice::Current &) const992 ServerI::isEnabled(const ::Ice::Current&) const
993 {
994 Lock sync(*this);
995 checkDestroyed();
996 return _activation != Disabled;
997 }
998
999 void
setProcess_async(const AMD_Server_setProcessPtr & amdCB,const Ice::ProcessPrx & process,const Ice::Current &)1000 ServerI::setProcess_async(const AMD_Server_setProcessPtr& amdCB, const Ice::ProcessPrx& process, const Ice::Current&)
1001 {
1002 bool deact = false;
1003 ServerAdapterDict adpts;
1004 ServerCommandPtr command;
1005 {
1006 Lock sync(*this);
1007 checkDestroyed();
1008 _process = process;
1009 if(_state == DeactivatingWaitForProcess)
1010 {
1011 deact = true;
1012 }
1013 else
1014 {
1015 if(checkActivation())
1016 {
1017 adpts = _adapters;
1018 }
1019 command = nextCommand();
1020 }
1021 }
1022 amdCB->ice_response();
1023
1024 for(ServerAdapterDict::iterator r = adpts.begin(); r != adpts.end(); ++r)
1025 {
1026 try
1027 {
1028 r->second->activationCompleted();
1029 }
1030 catch(const Ice::ObjectNotExistException&)
1031 {
1032 }
1033 }
1034
1035 if(deact)
1036 {
1037 deactivate();
1038 }
1039
1040 if(command)
1041 {
1042 command->execute();
1043 }
1044 }
1045
1046 Ice::Long
getOffsetFromEnd(const string & filename,int count,const Ice::Current &) const1047 ServerI::getOffsetFromEnd(const string& filename, int count, const Ice::Current&) const
1048 {
1049 return _node->getFileCache()->getOffsetFromEnd(getFilePath(filename), count);
1050 }
1051
1052 bool
read(const string & filename,Ice::Long pos,int size,Ice::Long & newPos,Ice::StringSeq & lines,const Ice::Current &) const1053 ServerI::read(const string& filename, Ice::Long pos, int size, Ice::Long& newPos, Ice::StringSeq& lines,
1054 const Ice::Current&) const
1055 {
1056 return _node->getFileCache()->read(getFilePath(filename), pos, size, newPos, lines);
1057 }
1058
1059 bool
isAdapterActivatable(const string & id) const1060 ServerI::isAdapterActivatable(const string& id) const
1061 {
1062 Lock sync(*this);
1063 if(!_desc || _activation == Disabled)
1064 {
1065 return false;
1066 }
1067
1068 if(_desc->activation == "manual" ||
1069 (_desc->activation == "session" && _desc->sessionId.empty()))
1070 {
1071 return false;
1072 }
1073
1074 if(_state <= WaitForActivation)
1075 {
1076 if(_activatedAdapters.find(id) != _activatedAdapters.end())
1077 {
1078 return false; // The adapter was already activated once.
1079 }
1080 return true;
1081 }
1082 else if(_state < Deactivating)
1083 {
1084 return false; // The server is active or its activation timed out.
1085 }
1086 else if(_state < Destroying)
1087 {
1088 return _node->getActivator()->isActive(); // The server is being deactivated and the
1089 // node isn't shutting down yet.
1090 }
1091 else
1092 {
1093 return false;
1094 }
1095 }
1096
1097 const string&
getId() const1098 ServerI::getId() const
1099 {
1100 return _id;
1101 }
1102
1103 InternalDistributionDescriptorPtr
getDistribution() const1104 ServerI::getDistribution() const
1105 {
1106 Lock sync(*this);
1107 return _desc ? _desc->distrib : InternalDistributionDescriptorPtr();
1108 }
1109
1110 bool
dependsOnApplicationDistrib() const1111 ServerI::dependsOnApplicationDistrib() const
1112 {
1113 Lock sync(*this);
1114 return _desc ? _desc->applicationDistrib : false;
1115 }
1116
1117 void
start(ServerActivation activation,const AMD_Server_startPtr & amdCB)1118 ServerI::start(ServerActivation activation, const AMD_Server_startPtr& amdCB)
1119 {
1120 ServerCommandPtr command;
1121 {
1122 Lock sync(*this);
1123 checkDestroyed();
1124
1125 //
1126 // Eventually re-enable the server if it's disabled because of a failure.
1127 //
1128 if(_disableOnFailure > 0 && _failureTime != IceUtil::Time())
1129 {
1130 if(activation == Manual ||
1131 (_failureTime + IceUtil::Time::seconds(_disableOnFailure) <
1132 IceUtil::Time::now(IceUtil::Time::Monotonic)))
1133 {
1134 _activation = _previousActivation;
1135 _failureTime = IceUtil::Time();
1136 }
1137 }
1138
1139 //
1140 // Check the current activation mode and the requested activation.
1141 //
1142 if(_activation == Disabled)
1143 {
1144 throw ServerStartException(_id, "The server is disabled.");
1145 }
1146 else if(_activation != Always && activation == Always)
1147 {
1148 assert(!amdCB);
1149 return; // Nothing to do.
1150 }
1151 else if(_activation == Manual && activation != Manual)
1152 {
1153 throw ServerStartException(_id, "The server activation doesn't allow this activation mode.");
1154 }
1155 else if(_activation == Session && _desc->sessionId.empty())
1156 {
1157 throw ServerStartException(_id, "The server is not owned by a session.");
1158 }
1159
1160 //
1161 // Check the current state.
1162 //
1163 if(_state == ActivationTimeout)
1164 {
1165 throw ServerStartException(_id, "The server activation timed out.");
1166 }
1167 else if(_state == Active)
1168 {
1169 if(activation == Always)
1170 {
1171 return; // Nothing to do, it's already active (and we
1172 // don't want to throw because it would be
1173 // considered as an error.)
1174 }
1175 throw ServerStartException(_id, "The server is already active.");
1176 }
1177 else if(_state == Destroying)
1178 {
1179 throw ServerStartException(_id, "The server is being destroyed.");
1180 }
1181
1182 if(_timerTask)
1183 {
1184 _node->getTimer()->cancel(_timerTask);
1185 _timerTask = 0;
1186 }
1187
1188 if(!_start)
1189 {
1190 _start = new StartCommand(this, _node->getTimer(), _activationTimeout);
1191 }
1192 if(amdCB)
1193 {
1194 _start->addCallback(amdCB);
1195 }
1196 command = nextCommand();
1197 }
1198 if(command)
1199 {
1200 command->execute();
1201 }
1202 }
1203
1204 ServerCommandPtr
load(const AMD_Node_loadServerPtr & amdCB,const InternalServerDescriptorPtr & desc,const string & replicaName,bool noRestart)1205 ServerI::load(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescriptorPtr& desc, const string& replicaName,
1206 bool noRestart)
1207 {
1208 Lock sync(*this);
1209 checkDestroyed();
1210 checkRevision(replicaName, desc->uuid, desc->revision);
1211
1212 //
1213 // Otherwise, if the following conditions are met:
1214 //
1215 // - the server is already loaded.
1216 // - the descriptor is from the master and the session id didn't change or it's coming from a slave.
1217 // - the descriptor is the same as the one loaded.
1218 //
1219 // we don't re-load the server. We just return the server
1220 // proxy and the proxies of its adapters.
1221 //
1222 InternalServerDescriptorPtr d = _load ? _load->getInternalServerDescriptor() : _desc;
1223 if(d && (replicaName != "Master" || d->sessionId == desc->sessionId) && !descriptorUpdated(d, desc))
1224 {
1225 if(d->revision != desc->revision)
1226 {
1227 updateRevision(desc->uuid, desc->revision);
1228 }
1229
1230 if(!_desc || (_load && descriptorUpdated(_load->getInternalServerDescriptor(), _desc)))
1231 {
1232 //
1233 // If the server initial loading didn't complete yet or there's a new updated descriptor
1234 // waiting to be loaded, we wait for the loading to complete before replying.
1235 //
1236 _load->addCallback(amdCB);
1237 return 0;
1238 }
1239 else if(amdCB)
1240 {
1241 AdapterPrxDict adapters;
1242 for(ServerAdapterDict::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p)
1243 {
1244 adapters.insert(make_pair(p->first, p->second->getProxy()));
1245 }
1246 amdCB->ice_response(_this, adapters, _activationTimeout, _deactivationTimeout);
1247 }
1248 return 0;
1249 }
1250
1251 if(!StopCommand::isStopped(_state) && !_stop) // Server is running and no stop is scheduled
1252 {
1253 assert(_desc);
1254 if(noRestart)
1255 {
1256 //
1257 // If the server is not inactive, we have to make sure the update doesn't require
1258 // a restart. If it requires a restart, we throw. Otherwise we update its properties
1259 // now.
1260 //
1261 checkNoRestart(desc);
1262 }
1263 else
1264 {
1265 _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout);
1266 }
1267 }
1268
1269 if(!_load)
1270 {
1271 _load = new LoadCommand(this, _desc, _node->getTraceLevels());
1272 }
1273 _load->setUpdate(desc, _destroy);
1274 if(_destroy && _state != Destroying)
1275 {
1276 _destroy->finished();
1277 _destroy = 0;
1278 }
1279
1280 if(_stop || StopCommand::isStopped(_state))
1281 {
1282 _load->addCallback(amdCB); // Load will return once the server is loaded.
1283 }
1284 else
1285 {
1286 if(_state >= ServerI::Activating && _state < ServerI::Active)
1287 {
1288 //
1289 // If the server is being activated, return the response
1290 // now. We can't wait for runtime properties to be updated
1291 // as this could cause a deadlock if the registry needs
1292 // the server proxy to register the server process proxy
1293 // with the node.
1294 //
1295 AdapterPrxDict adapters;
1296 for(ServerAdapterDict::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p)
1297 {
1298 adapters.insert(make_pair(p->first, p->second->getProxy()));
1299 }
1300 amdCB->ice_response(_this, adapters, _activationTimeout, _deactivationTimeout);
1301 }
1302 else if(_state == ServerI::Active)
1303 {
1304 _load->addCallback(amdCB); // Must be called before startRuntimePropertiesUpdate!
1305 updateRevision(desc->uuid, desc->revision);
1306 _load->startRuntimePropertiesUpdate(_process);
1307 }
1308 else
1309 {
1310 _load->addCallback(amdCB);
1311 }
1312 }
1313 return nextCommand();
1314 }
1315
1316 bool
checkUpdate(const InternalServerDescriptorPtr & desc,bool noRestart,const Ice::Current &)1317 ServerI::checkUpdate(const InternalServerDescriptorPtr& desc, bool noRestart, const Ice::Current&)
1318 {
1319 Lock sync(*this);
1320 checkDestroyed();
1321
1322 if(!_desc)
1323 {
1324 throw DeploymentException("server not loaded");
1325 }
1326
1327 if(!desc)
1328 {
1329 if(noRestart && !StopCommand::isStopped(_state) && !_stop)
1330 {
1331 throw DeploymentException("the server is running");
1332 }
1333 return true;
1334 }
1335
1336 InternalServerDescriptorPtr d = _load ? _load->getInternalServerDescriptor() : _desc;
1337 if(!descriptorUpdated(d, desc))
1338 {
1339 return StopCommand::isStopped(_state);
1340 }
1341
1342 if(noRestart)
1343 {
1344 checkNoRestart(desc);
1345 }
1346
1347 try
1348 {
1349 checkAndUpdateUser(desc, false); // false = don't update the user, just check.
1350 }
1351 catch(const exception& ex)
1352 {
1353 throw DeploymentException(ex.what());
1354 }
1355
1356 return StopCommand::isStopped(_state);
1357 }
1358
1359 void
checkRemove(bool noRestart,const Ice::Current &)1360 ServerI::checkRemove(bool noRestart, const Ice::Current&)
1361 {
1362 Lock sync(*this);
1363 checkDestroyed();
1364
1365 if(noRestart && !StopCommand::isStopped(_state) && !_stop)
1366 {
1367 throw DeploymentException("the server is running");
1368 }
1369 }
1370
1371 ServerCommandPtr
destroy(const AMD_Node_destroyServerPtr & amdCB,const string & uuid,int revision,const string & replicaName,bool noRestart)1372 ServerI::destroy(const AMD_Node_destroyServerPtr& amdCB, const string& uuid, int revision, const string& replicaName,
1373 bool noRestart)
1374 {
1375 Lock sync(*this);
1376 checkDestroyed();
1377 checkRevision(replicaName, uuid, revision);
1378
1379 if(!_desc)
1380 {
1381 amdCB->ice_response();
1382 return 0; // Server is already destroyed.
1383 }
1384
1385 if(!StopCommand::isStopped(_state) && !_stop)
1386 {
1387 if(noRestart)
1388 {
1389 throw DeploymentException("removal requires server to be stopped");
1390 }
1391 _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout);
1392 }
1393
1394 if(!_destroy)
1395 {
1396 //
1397 // If uuid is empty, the destroy call comes from the consistency check. In
1398 // this case, we clear the server directory only if it contains non-user data.
1399 //
1400 _destroy = new DestroyCommand(this, false, !uuid.empty());
1401 }
1402 if(amdCB)
1403 {
1404 _destroy->addCallback(amdCB);
1405 }
1406 return nextCommand();
1407 }
1408
1409 bool
startPatch(bool shutdown)1410 ServerI::startPatch(bool shutdown)
1411 {
1412 ServerCommandPtr command;
1413 {
1414 Lock sync(*this);
1415 checkDestroyed();
1416 if(!StopCommand::isStopped(_state))
1417 {
1418 if(!shutdown)
1419 {
1420 return false;
1421 }
1422 else if(!_stop)
1423 {
1424 _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout);
1425 }
1426 }
1427 if(!_patch)
1428 {
1429 _patch = new PatchCommand(this);
1430 }
1431 command = nextCommand();
1432 }
1433 if(command)
1434 {
1435 command->execute();
1436 }
1437 return true;
1438 }
1439
1440 bool
waitForPatch()1441 ServerI::waitForPatch()
1442 {
1443 PatchCommandPtr patch;
1444 {
1445 Lock sync(*this);
1446 if(!_patch)
1447 {
1448 return true;
1449 }
1450 patch = _patch;
1451 }
1452 return patch->waitForPatch();
1453 }
1454
1455 void
finishPatch()1456 ServerI::finishPatch()
1457 {
1458 #ifndef _WIN32
1459 {
1460 Lock sync(*this);
1461 try
1462 {
1463 chownRecursive(_serverDir + "/distrib", _uid, _gid);
1464 }
1465 catch(const exception& ex)
1466 {
1467 Ice::Warning out(_node->getTraceLevels()->logger);
1468 out << ex.what();
1469 }
1470 }
1471 #endif
1472 setState(ServerI::Inactive);
1473 }
1474
1475 void
adapterActivated(const string & id)1476 ServerI::adapterActivated(const string& id)
1477 {
1478 ServerCommandPtr command;
1479 ServerAdapterDict adpts;
1480 {
1481 Lock sync(*this);
1482 if(_state != ServerI::Activating &&
1483 _state != ServerI::WaitForActivation &&
1484 _state != ServerI::ActivationTimeout)
1485 {
1486 return;
1487 }
1488 _activatedAdapters.insert(id);
1489 if(checkActivation())
1490 {
1491 adpts = _adapters;
1492 }
1493 command = nextCommand();
1494 }
1495 for(ServerAdapterDict::iterator r = adpts.begin(); r != adpts.end(); ++r)
1496 {
1497 if(r->first != id)
1498 {
1499 try
1500 {
1501 r->second->activationCompleted();
1502 }
1503 catch(const Ice::ObjectNotExistException&)
1504 {
1505 }
1506 }
1507 }
1508 if(command)
1509 {
1510 command->execute();
1511 }
1512 }
1513
1514 void
adapterDeactivated(const string & id)1515 ServerI::adapterDeactivated(const string& id)
1516 {
1517 ServerCommandPtr command;
1518 {
1519 Lock sync(*this);
1520 while(_state == ServerI::Activating)
1521 {
1522 wait(); // Wait for activate() to set the state to WaitForActivation
1523 }
1524
1525 if((_state == Active || _state == WaitForActivation) &&
1526 _serverLifetimeAdapters.find(id) != _serverLifetimeAdapters.end())
1527 {
1528 _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout, false);
1529 }
1530 command = nextCommand();
1531 }
1532 if(command)
1533 {
1534 command->execute();
1535 }
1536 }
1537
1538 void
checkDestroyed() const1539 ServerI::checkDestroyed() const
1540 {
1541 if(_state == Destroyed)
1542 {
1543 throw Ice::ObjectNotExistException(__FILE__, __LINE__, _this->ice_getIdentity(), "", "");
1544 }
1545 }
1546
1547 void
disableOnFailure()1548 ServerI::disableOnFailure()
1549 {
1550 //
1551 // If the server is already disabled, nothing to do.
1552 //
1553 if(_activation == Disabled)
1554 {
1555 return;
1556 }
1557
1558 //
1559 // If disable on failure is configured or if the activation mode
1560 // is always and the server wasn't active at the time of the
1561 // failure we disable the server.
1562 //
1563 if(_disableOnFailure != 0 || (_activation == Always && (_state == Activating || _state == WaitForActivation)))
1564 {
1565 _previousActivation = _activation;
1566 _activation = Disabled;
1567 _failureTime = IceUtil::Time::now(IceUtil::Time::Monotonic);
1568 }
1569 }
1570
1571 void
activationTimedOut()1572 ServerI::activationTimedOut()
1573 {
1574 ServerCommandPtr command;
1575 ServerAdapterDict adapters;
1576 {
1577 Lock sync(*this);
1578 if(_state != ServerI::WaitForActivation)
1579 {
1580 return;
1581 }
1582
1583 setStateNoSync(ServerI::ActivationTimeout, "The server activation timed out.");
1584
1585 if(_node->getTraceLevels()->server > 1)
1586 {
1587 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
1588 out << "server `" << _id << "' activation timed out";
1589 }
1590 adapters = _adapters;
1591 command = nextCommand();
1592 }
1593
1594 for(ServerAdapterDict::const_iterator p = adapters.begin(); p != adapters.end(); ++p)
1595 {
1596 try
1597 {
1598 p->second->activationFailed("server activation timed out");
1599 }
1600 catch(const Ice::ObjectNotExistException&)
1601 {
1602 }
1603 }
1604
1605 if(command)
1606 {
1607 command->execute();
1608 }
1609 }
1610
1611 void
activate()1612 ServerI::activate()
1613 {
1614 InternalServerDescriptorPtr desc;
1615 ServerAdapterDict adpts;
1616 bool waitForReplication;
1617
1618 #ifndef _WIN32
1619 uid_t uid;
1620 gid_t gid;
1621 #endif
1622 string failure;
1623 try
1624 {
1625 {
1626 Lock sync(*this);
1627 assert(_state == Activating && _desc);
1628 desc = _desc;
1629 adpts = _adapters;
1630
1631 if(_activation == Disabled)
1632 {
1633 throw runtime_error("The server is disabled.");
1634 }
1635
1636 //
1637 // The first time the server is started, we ensure that the
1638 // replication of its descriptor is completed. This is to make
1639 // sure all the replicas are up to date when the server
1640 // starts for the first time with a given descriptor.
1641 //
1642 waitForReplication = _waitForReplication;
1643 _waitForReplication = false;
1644
1645 _process = 0;
1646
1647 #ifndef _WIN32
1648 uid = _uid;
1649 gid = _gid;
1650 #endif
1651 }
1652
1653 //
1654 // We first ensure that the application is replicated on all the
1655 // registries before to start the server. We only do this each
1656 // time the server is updated or initialy loaded on the node.
1657 //
1658 if(waitForReplication)
1659 {
1660 NodeSessionPrx session = _node->getMasterNodeSession();
1661 if(session)
1662 {
1663 _node->getMasterNodeSession()->begin_waitForApplicationUpdate(
1664 desc->uuid, desc->revision, ::Ice::newCallback(this, &ServerI::waitForApplicationUpdateCompleted));
1665 return;
1666 }
1667 }
1668
1669 //
1670 // Compute the server command line options.
1671 //
1672 Ice::StringSeq options;
1673 for(Ice::StringSeq::const_iterator p = desc->options.begin(); p != desc->options.end(); ++p)
1674 {
1675 if(!p->empty())
1676 {
1677 options.push_back(*p);
1678 }
1679 }
1680 options.push_back("--Ice.Config=" + escapeProperty(_serverDir + "/config/config"));
1681
1682 Ice::StringSeq envs;
1683 transform(desc->envs.begin(), desc->envs.end(), back_inserter(envs), EnvironmentEval());
1684
1685 //
1686 // Clear the adapters direct proxy (this is usefull if the server
1687 // was manually activated).
1688 //
1689 for(ServerAdapterDict::iterator p = adpts.begin(); p != adpts.end(); ++p)
1690 {
1691 try
1692 {
1693 p->second->clear();
1694 }
1695 catch(const Ice::ObjectNotExistException&)
1696 {
1697 }
1698 }
1699
1700 #ifndef _WIN32
1701 int pid = _node->getActivator()->activate(desc->id, desc->exe, desc->pwd, uid, gid, options, envs, this);
1702 #else
1703 int pid = _node->getActivator()->activate(desc->id, desc->exe, desc->pwd, options, envs, this);
1704 #endif
1705 ServerCommandPtr command;
1706 bool active = false;
1707 {
1708 Lock sync(*this);
1709 assert(_state == Activating);
1710 _pid = pid;
1711 setStateNoSync(ServerI::WaitForActivation);
1712 active = checkActivation();
1713 command = nextCommand();
1714 notifyAll(); // Terminated might be waiting for the state change.
1715 }
1716 if(active)
1717 {
1718 for(ServerAdapterDict::iterator r = adpts.begin(); r != adpts.end(); ++r)
1719 {
1720 try
1721 {
1722 r->second->activationCompleted();
1723 }
1724 catch(const Ice::ObjectNotExistException&)
1725 {
1726 }
1727 }
1728 }
1729 if(command)
1730 {
1731 command->execute();
1732 }
1733 return;
1734 }
1735 catch(const Ice::Exception& ex)
1736 {
1737 Ice::Warning out(_node->getTraceLevels()->logger);
1738 out << "activation failed for server `" << _id << "':\n";
1739 out << ex;
1740
1741 failure = ex.what();
1742 }
1743 catch(const std::exception& ex)
1744 {
1745 failure = ex.what();
1746 }
1747
1748 {
1749 Lock sync(*this);
1750 disableOnFailure();
1751 setStateNoSync(ServerI::Deactivating, failure);
1752 }
1753
1754 for(ServerAdapterDict::iterator r = adpts.begin(); r != adpts.end(); ++r)
1755 {
1756 try
1757 {
1758 r->second->activationFailed(failure);
1759 }
1760 catch(const Ice::ObjectNotExistException&)
1761 {
1762 }
1763 }
1764
1765 setState(ServerI::Inactive);
1766 }
1767
1768 void
kill()1769 ServerI::kill()
1770 {
1771 {
1772 Lock sync(*this);
1773 if(_state != Destroying && _state != Deactivating && _state != DeactivatingWaitForProcess)
1774 {
1775 return;
1776 }
1777 }
1778
1779 try
1780 {
1781 _node->getActivator()->kill(_id);
1782 }
1783 catch(const Ice::SyscallException& ex)
1784 {
1785 Ice::Warning out(_node->getTraceLevels()->logger);
1786 out << "deactivation failed for server `" << _id << "':\n";
1787 out << ex;
1788 setState(ServerI::Inactive); // TODO: Is this really correct?
1789 }
1790 }
1791
1792 void
deactivate()1793 ServerI::deactivate()
1794 {
1795 Ice::ProcessPrx process;
1796 {
1797 Lock sync(*this);
1798 if(_state != Deactivating && _state != DeactivatingWaitForProcess)
1799 {
1800 return;
1801 }
1802
1803 assert(_desc);
1804
1805 //
1806 // If a process object is supposed to be registered and it's
1807 // not set yet, we wait for the server to set this process
1808 // object before attempting to deactivate the server again.
1809 //
1810 if(_desc->processRegistered && !_process)
1811 {
1812 setStateNoSync(ServerI::DeactivatingWaitForProcess);
1813 return;
1814 }
1815 process = _process;
1816 }
1817
1818 try
1819 {
1820 //
1821 // Deactivate the server and for the termination of the server.
1822 //
1823 _node->getActivator()->deactivate(_id, process);
1824 return;
1825 }
1826 catch(const Ice::Exception& ex)
1827 {
1828 Ice::Warning out(_node->getTraceLevels()->logger);
1829 out << "graceful server shutdown failed, killing server `" << _id << "':\n";
1830 out << ex;
1831 }
1832
1833 try
1834 {
1835 //
1836 // If we couldn't deactivate it we kill it.
1837 //
1838 _node->getActivator()->kill(_id);
1839 return;
1840 }
1841 catch(const Ice::SyscallException& ex)
1842 {
1843 Ice::Warning out(_node->getTraceLevels()->logger);
1844 out << "deactivation failed for server `" << _id << "':\n";
1845 out << ex;
1846 setState(ServerI::Inactive); // TODO: Is this really correct?
1847 }
1848 }
1849
1850 void
destroy()1851 ServerI::destroy()
1852 {
1853 ServerAdapterDict adpts;
1854 {
1855 Lock sync(*this);
1856 assert(_desc);
1857 assert(_state == Destroying);
1858 adpts = _adapters;
1859 }
1860
1861 _node->removeServer(this, _desc->application);
1862
1863 //
1864 // Remove the server directory only if the clear dir flag is set (user
1865 // explicitly destroyed the server) or if the server directory doesn't
1866 // contain user data).
1867 //
1868 if(_destroy->clearDir() || _node->canRemoveServerDirectory(_id))
1869 {
1870 try
1871 {
1872 IcePatch2Internal::removeRecursive(_serverDir);
1873 }
1874 catch(const exception& ex)
1875 {
1876 if(!_destroy->loadFailure())
1877 {
1878 Ice::Warning out(_node->getTraceLevels()->logger);
1879 out << "removing server directory `" << _serverDir << "' failed:\n" << ex.what();
1880 }
1881 }
1882 }
1883
1884 //
1885 // Destroy the object adapters.
1886 //
1887 for(ServerAdapterDict::const_iterator p = adpts.begin(); p != adpts.end(); ++p)
1888 {
1889 try
1890 {
1891 p->second->destroy();
1892 }
1893 catch(const Ice::LocalException&)
1894 {
1895 }
1896 }
1897
1898 setState(Destroyed);
1899 }
1900
1901 void
terminated(const string & msg,int status)1902 ServerI::terminated(const string& msg, int status)
1903 {
1904 ServerAdapterDict adpts;
1905 {
1906 Lock sync(*this);
1907 while(_state == ServerI::Activating)
1908 {
1909 wait(); // Wait for activate() to set the state to WaitForActivation
1910 }
1911
1912 adpts = _adapters;
1913 _activatedAdapters.clear();
1914 _pid = 0;
1915
1916 bool failed = false;
1917 #ifndef _WIN32
1918 failed = WIFEXITED(status) && WEXITSTATUS(status) != 0;
1919 if(WIFSIGNALED(status))
1920 {
1921 int s = WTERMSIG(status);
1922 failed = s == SIGABRT || s == SIGILL || s == SIGBUS || s == SIGFPE || s == SIGSEGV;
1923 }
1924 #else
1925 failed = status != 0;
1926 #endif
1927 if(failed)
1928 {
1929 disableOnFailure();
1930 }
1931
1932 if(_state != ServerI::Deactivating &&
1933 _state != ServerI::DeactivatingWaitForProcess &&
1934 _state != ServerI::Destroying)
1935 {
1936 ostringstream os;
1937 os << "The server terminated unexpectedly";
1938 #ifndef _WIN32
1939 if(WIFEXITED(status))
1940 {
1941 os << " with exit code " << WEXITSTATUS(status);
1942 }
1943 else if(WIFSIGNALED(status))
1944 {
1945 os << " with signal " << signalToString(WTERMSIG(status));
1946 }
1947 #else
1948 os << " with exit code " << status;
1949 #endif
1950 os << (msg.empty() ? string(".") : ":\n" + msg);
1951 setStateNoSync(ServerI::Deactivating, os.str());
1952 }
1953 }
1954
1955 //
1956 // The server has terminated, set its adapter direct proxies to
1957 // null to cause the server re-activation if one of its adapter
1958 // direct proxy is requested.
1959 //
1960 for(ServerAdapterDict::iterator p = adpts.begin(); p != adpts.end(); ++p)
1961 {
1962 try
1963 {
1964 p->second->setDirectProxy(0, Ice::emptyCurrent);
1965 }
1966 catch(const Ice::ObjectNotExistException&)
1967 {
1968 }
1969 }
1970
1971 bool doDestroy = false;
1972 ServerCommandPtr command;
1973 {
1974 Lock sync(*this);
1975 if(_state == ServerI::Destroying)
1976 {
1977 doDestroy = true;
1978 }
1979 else
1980 {
1981 setStateNoSync(ServerI::Inactive);
1982 command = nextCommand();
1983 }
1984 }
1985 if(doDestroy)
1986 {
1987 destroy();
1988 }
1989 else if(command)
1990 {
1991 command->execute();
1992 }
1993 }
1994
1995 void
shutdown()1996 ServerI::shutdown()
1997 {
1998 Lock sync(*this);
1999 assert(_state == ServerI::Inactive);
2000 assert(!_destroy);
2001 assert(!_stop);
2002 assert(!_load);
2003 assert(!_patch);
2004 assert(!_start);
2005 _timerTask = 0;
2006 }
2007
2008 void
update()2009 ServerI::update()
2010 {
2011 ServerCommandPtr command;
2012 {
2013 Lock sync(*this);
2014 if(_state != ServerI::Loading)
2015 {
2016 return;
2017 }
2018
2019 InternalServerDescriptorPtr oldDescriptor = _desc;
2020 bool disabled = oldDescriptor && _activation == Disabled;
2021 try
2022 {
2023 if(_load->clearDir())
2024 {
2025 //
2026 // The server was explicitely destroyed then updated,
2027 // we first need to cleanup the directory to remove
2028 // any user created files.
2029 //
2030 try
2031 {
2032 IcePatch2Internal::removeRecursive(_serverDir);
2033 }
2034 catch(const exception&)
2035 {
2036 }
2037 }
2038
2039 try
2040 {
2041 updateImpl(_load->getInternalServerDescriptor());
2042 }
2043 catch(const exception& ex)
2044 {
2045 throw DeploymentException(ex.what());
2046 }
2047
2048 if(oldDescriptor)
2049 {
2050 if(oldDescriptor->application != _desc->application)
2051 {
2052 _node->removeServer(this, oldDescriptor->application);
2053 _node->addServer(this, _desc->application);
2054 }
2055
2056 if(_node->getTraceLevels()->server > 0)
2057 {
2058 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
2059 out << "updated configuration for server `" << _id << "'";
2060 }
2061 }
2062 else
2063 {
2064 _node->addServer(this, _desc->application);
2065 }
2066
2067 AdapterPrxDict adapters;
2068 for(ServerAdapterDict::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p)
2069 {
2070 adapters.insert(make_pair(p->first, p->second->getProxy()));
2071 }
2072 _load->finished(_this, adapters, _activationTimeout, _deactivationTimeout);
2073 }
2074 catch(const DeploymentException& ex)
2075 {
2076 //
2077 // Rollback old descriptor.
2078 //
2079 if(oldDescriptor)
2080 {
2081 try
2082 {
2083 updateImpl(oldDescriptor);
2084 }
2085 catch(const Ice::Exception& e)
2086 {
2087 Ice::Warning out(_node->getTraceLevels()->logger);
2088 out << "update failed:\n" << ex.reason << "\nand couldn't rollback old descriptor:\n" << e;
2089 }
2090 catch(const exception& e)
2091 {
2092 Ice::Warning out(_node->getTraceLevels()->logger);
2093 out << "update failed:\n" << ex.reason << "\nand couldn't rollback old descriptor:\n" << e.what();
2094 }
2095 }
2096 else if(!_destroy)
2097 {
2098 _destroy = new DestroyCommand(this, true, true);
2099 }
2100
2101 _load->failed(ex);
2102 }
2103
2104 if(oldDescriptor && disabled != (_activation == Disabled))
2105 {
2106 _node->observerUpdateServer(getDynamicInfo());
2107 }
2108 setStateNoSync(Inactive);
2109 command = nextCommand();
2110 }
2111 if(command)
2112 {
2113 command->execute();
2114 }
2115 }
2116
2117 void
updateImpl(const InternalServerDescriptorPtr & descriptor)2118 ServerI::updateImpl(const InternalServerDescriptorPtr& descriptor)
2119 {
2120 assert(_load && descriptor);
2121
2122 _desc = descriptor;
2123 _waitForReplication = true;
2124
2125 //
2126 // Remember if the server was just released by a session, this
2127 // will be used later to not update the configuration on the disk
2128 // (as an optimization and to allow users to review the
2129 // configuration file after allocating a server -- that's useful
2130 // if the server configuration is bogus and the session server
2131 // can't start).
2132 //
2133 bool serverSessionReleased = _desc && _desc->activation == "session" &&
2134 _desc->revision == descriptor->revision && !_desc->sessionId.empty() && descriptor->sessionId.empty();
2135
2136 //
2137 // Go through the adapters and create the object adapter Ice
2138 // objects if necessary, also remove the old ones.
2139 //
2140 {
2141 ServerAdapterDict oldAdapters;
2142 oldAdapters.swap(_adapters);
2143 _serverLifetimeAdapters.clear();
2144 Ice::ObjectAdapterPtr adapter = _node->getAdapter();
2145 for(InternalAdapterDescriptorSeq::const_iterator r = _desc->adapters.begin(); r != _desc->adapters.end(); ++r)
2146 {
2147 try
2148 {
2149 Ice::Identity id;
2150 id.category = _this->ice_getIdentity().category + "Adapter";
2151 id.name = _id + "-" + (*r)->id;
2152 ServerAdapterIPtr servant = ServerAdapterIPtr::dynamicCast(adapter->find(id));
2153 if(!servant)
2154 {
2155 AdapterPrx proxy = AdapterPrx::uncheckedCast(adapter->createProxy(id));
2156 servant = new ServerAdapterI(_node, this, _id, proxy, (*r)->id, _activation != Disabled ||
2157 _failureTime != IceUtil::Time());
2158 adapter->add(servant, id);
2159 }
2160 _adapters.insert(make_pair((*r)->id, servant));
2161
2162 if((*r)->serverLifetime)
2163 {
2164 _serverLifetimeAdapters.insert((*r)->id);
2165 }
2166 }
2167 catch(const Ice::ObjectAdapterDeactivatedException&)
2168 {
2169 // IGNORE
2170 }
2171 catch(const Ice::LocalException& ex)
2172 {
2173 Ice::Error out(_node->getTraceLevels()->logger);
2174 out << "couldn't add adapter `" << (*r)->id << "':\n" << ex;
2175 }
2176 oldAdapters.erase((*r)->id);
2177 }
2178
2179 //
2180 // Remove old object adapters.
2181 //
2182 for(ServerAdapterDict::const_iterator t = oldAdapters.begin(); t != oldAdapters.end(); ++t)
2183 {
2184 try
2185 {
2186 t->second->destroy();
2187 }
2188 catch(const Ice::ObjectAdapterDeactivatedException&)
2189 {
2190 // IGNORE
2191 }
2192 catch(const Ice::LocalException& ex)
2193 {
2194 Ice::Error out(_node->getTraceLevels()->logger);
2195 out << "couldn't destroy adapter `" << t->first << "':\n" << ex;
2196 }
2197 }
2198 }
2199
2200 //
2201 // If the server was disabled because it failed (or because it's
2202 // the first time it's being updated). Set the activation mode
2203 // based on the descriptor activation. Otherwise, if the server is
2204 // disabled and failure time isn't set, we don't change the
2205 // activation since the user explicitely disabled the server.
2206 //
2207 if(_activation != Disabled || _failureTime != IceUtil::Time())
2208 {
2209 _activation = toServerActivation(_desc->activation);
2210 _failureTime = IceUtil::Time();
2211 }
2212
2213 if(_timerTask)
2214 {
2215 _node->getTimer()->cancel(_timerTask);
2216 _timerTask = 0;
2217 }
2218
2219 checkAndUpdateUser(_desc, true); // we pass true to update _uid/_gid.
2220
2221 istringstream at(_desc->activationTimeout);
2222 if(!(at >> _activationTimeout) || !at.eof() || _activationTimeout == 0)
2223 {
2224 _activationTimeout = _waitTime;
2225 }
2226 istringstream dt(_desc->deactivationTimeout);
2227 if(!(dt >> _deactivationTimeout) || !dt.eof() || _deactivationTimeout == 0)
2228 {
2229 _deactivationTimeout = _waitTime;
2230 }
2231
2232 //
2233 // Simplify the log paths and transform relative paths into
2234 // absolute paths, also make sure the logs are sorted.
2235 //
2236 for(Ice::StringSeq::const_iterator p = _desc->logs.begin(); p != _desc->logs.end(); ++p)
2237 {
2238 string path = IcePatch2Internal::simplify(*p);
2239 if(IceUtilInternal::isAbsolutePath(path))
2240 {
2241 _logs.push_back(path);
2242 }
2243 else
2244 {
2245 _logs.push_back(_node->getPlatformInfo().getCwd() + '/' + path);
2246 }
2247 }
2248 sort(_logs.begin(), _logs.begin());
2249
2250 PropertyDescriptorSeqDict properties = getProperties(_desc);
2251 PropertyDescriptorSeq& props = properties["config"];
2252 _stdErrFile = getProperty(props, "Ice.StdErr");
2253 _stdOutFile = getProperty(props, "Ice.StdOut");
2254
2255 //
2256 // If the server is a session server and it wasn't udpated but
2257 // just released by a session, we don't update the configuration,
2258 // it will be done when the server is re-allocated.
2259 //
2260 if(serverSessionReleased)
2261 {
2262 return;
2263 }
2264
2265 //
2266 // Update the revision file.
2267 //
2268 updateRevision(_desc->uuid, _desc->revision);
2269
2270 //
2271 // Create or update the server directories exists.
2272 //
2273 IcePatch2Internal::createDirectory(_serverDir);
2274 IcePatch2Internal::createDirectory(_serverDir + "/config");
2275 IcePatch2Internal::createDirectory(_serverDir + "/dbs");
2276 IcePatch2Internal::createDirectory(_serverDir + "/distrib");
2277 IcePatch2Internal::createDirectory(_serverDir + "/data");
2278
2279 //
2280 // Create the configuration files, remove the old ones.
2281 //
2282 {
2283 //
2284 // We do not want to escape the properties if the Ice version is
2285 // previous to Ice 3.3.
2286 //
2287 Ice::StringSeq knownFiles;
2288 for(PropertyDescriptorSeqDict::const_iterator p = properties.begin(); p != properties.end(); ++p)
2289 {
2290 knownFiles.push_back(p->first);
2291
2292 const string configFilePath = _serverDir + "/config/" + p->first;
2293 ofstream configfile(IceUtilInternal::streamFilename(configFilePath).c_str()); // configFilePath is a UTF-8 string
2294 if(!configfile.good())
2295 {
2296 throw runtime_error("couldn't create configuration file: " + configFilePath);
2297 }
2298 configfile << "# Configuration file (" << IceUtil::Time::now().toDateTime() << ")" << endl << endl;
2299 for(PropertyDescriptorSeq::const_iterator r = p->second.begin(); r != p->second.end(); ++r)
2300 {
2301 if(r->value.empty() && r->name.find('#') == 0)
2302 {
2303 configfile << r->name << endl;
2304 }
2305 else
2306 {
2307 configfile << r->name << "=" << r->value << endl;
2308 }
2309 }
2310 configfile.close();
2311 }
2312 sort(knownFiles.begin(), knownFiles.end());
2313
2314 //
2315 // Remove old configuration files.
2316 //
2317 Ice::StringSeq files = IcePatch2Internal::readDirectory(_serverDir + "/config");
2318 Ice::StringSeq toDel;
2319 set_difference(files.begin(), files.end(), knownFiles.begin(), knownFiles.end(), back_inserter(toDel));
2320 for(Ice::StringSeq::const_iterator q = toDel.begin(); q != toDel.end(); ++q)
2321 {
2322 if(q->find("config_") == 0)
2323 {
2324 try
2325 {
2326 IcePatch2Internal::remove(_serverDir + "/config/" + *q);
2327 }
2328 catch(const exception& ex)
2329 {
2330 Ice::Warning out(_node->getTraceLevels()->logger);
2331 out << "couldn't remove file `" << _serverDir << "/config/" << *q << "':\n" << ex.what();
2332 }
2333 }
2334 }
2335 }
2336
2337 //
2338 // Update the service data directories if necessary and remove the old ones.
2339 //
2340 if(_desc->services)
2341 {
2342 Ice::StringSeq knownDirs;
2343 for(Ice::StringSeq::const_iterator q = _desc->services->begin(); q != _desc->services->end(); ++q)
2344 {
2345 knownDirs.push_back("data_" + *q);
2346 IcePatch2Internal::createDirectory(_serverDir + "/data_" + *q);
2347 }
2348 sort(knownDirs.begin(), knownDirs.end());
2349
2350 //
2351 // Remove old directories
2352 //
2353 Ice::StringSeq dirs = IcePatch2Internal::readDirectory(_serverDir);
2354 Ice::StringSeq svcDirs;
2355 for(Ice::StringSeq::const_iterator p = dirs.begin(); p != dirs.end(); ++p)
2356 {
2357 if(p->find("data_") == 0)
2358 {
2359 svcDirs.push_back(*p);
2360 }
2361 }
2362 Ice::StringSeq toDel;
2363 set_difference(svcDirs.begin(), svcDirs.end(), knownDirs.begin(), knownDirs.end(), back_inserter(toDel));
2364 for(Ice::StringSeq::const_iterator p = toDel.begin(); p != toDel.end(); ++p)
2365 {
2366 try
2367 {
2368 IcePatch2Internal::removeRecursive(_serverDir + "/" + *p);
2369 }
2370 catch(const exception& ex)
2371 {
2372 Ice::Warning out(_node->getTraceLevels()->logger);
2373 out << "couldn't remove directory `" << _serverDir << "/" << *p << "':\n" << ex.what();
2374 }
2375 }
2376 }
2377
2378 //
2379 // Update the database environments if necessary and remove the
2380 // old ones.
2381 //
2382 {
2383 Ice::StringSeq knownDbEnvs;
2384 for(InternalDbEnvDescriptorSeq::const_iterator q = _desc->dbEnvs.begin(); q != _desc->dbEnvs.end(); ++q)
2385 {
2386 knownDbEnvs.push_back((*q)->name);
2387
2388 string dbEnvHome = _serverDir + "/dbs/" + (*q)->name;
2389 IcePatch2Internal::createDirectory(dbEnvHome);
2390
2391 if(!(*q)->properties.empty())
2392 {
2393 string file = dbEnvHome + "/DB_CONFIG";
2394
2395 ofstream configfile(IceUtilInternal::streamFilename(file).c_str()); // file is a UTF-8 string
2396 if(!configfile.good())
2397 {
2398 throw runtime_error("couldn't create configuration file `" + file + "'");
2399 }
2400
2401 for(PropertyDescriptorSeq::const_iterator p = (*q)->properties.begin();
2402 p != (*q)->properties.end(); ++p)
2403 {
2404 if(!p->name.empty())
2405 {
2406 configfile << p->name;
2407 if(!p->value.empty())
2408 {
2409 configfile << " " << p->value;
2410 }
2411 configfile << endl;
2412 }
2413 }
2414 configfile.close();
2415 }
2416 }
2417 sort(knownDbEnvs.begin(), knownDbEnvs.end());
2418
2419 //
2420 // Remove old database environments.
2421 //
2422 Ice::StringSeq dbEnvs = IcePatch2Internal::readDirectory(_serverDir + "/dbs");
2423 Ice::StringSeq toDel;
2424 set_difference(dbEnvs.begin(), dbEnvs.end(), knownDbEnvs.begin(), knownDbEnvs.end(), back_inserter(toDel));
2425 for(Ice::StringSeq::const_iterator p = toDel.begin(); p != toDel.end(); ++p)
2426 {
2427 try
2428 {
2429 IcePatch2Internal::removeRecursive(_serverDir + "/dbs/" + *p);
2430 }
2431 catch(const exception& ex)
2432 {
2433 Ice::Warning out(_node->getTraceLevels()->logger);
2434 out << "couldn't remove directory `" << _serverDir << "/dbs/" << *p << "':\n" << ex.what();
2435 }
2436 }
2437 }
2438
2439 #ifndef _WIN32
2440 chownRecursive(_serverDir, _uid, _gid);
2441 #endif
2442 }
2443
2444 void
checkRevision(const string & replicaName,const string & uuid,int revision) const2445 ServerI::checkRevision(const string& replicaName, const string& uuid, int revision) const
2446 {
2447 if(replicaName == "Master")
2448 {
2449 return;
2450 }
2451
2452 string descUUID;
2453 int descRevision;
2454 if(_load)
2455 {
2456 descUUID = _load->getInternalServerDescriptor()->uuid;
2457 descRevision = _load->getInternalServerDescriptor()->revision;
2458 }
2459 else if(_desc)
2460 {
2461 descUUID = _desc->uuid;
2462 descRevision = _desc->revision;
2463 }
2464 else
2465 {
2466 string idFilePath = _serverDir + "/revision";
2467 ifstream is(IceUtilInternal::streamFilename(idFilePath).c_str()); // idFilePath is a UTF-8 string
2468 if(!is.good())
2469 {
2470 return;
2471 }
2472
2473 char line[1024];
2474 is.getline(line, 1024); // Ignore comments
2475 is.getline(line, 1024);
2476 is.getline(line, 1024);
2477 string ignored;
2478 is >> ignored >> descUUID;
2479 is >> ignored >> descRevision;
2480 }
2481
2482 if(uuid != descUUID)
2483 {
2484 throw DeploymentException("server from replica `" + replicaName + "' is from another application (`" + uuid +
2485 "')");
2486 }
2487 else if(revision != descRevision)
2488 {
2489 ostringstream os;
2490 os << "server from replica `" << replicaName << "' has a different version:\n"
2491 << "current revision: " << descRevision << "\nreplica revision: " << revision;
2492 throw DeploymentException(os.str());
2493 }
2494 }
2495
2496 void
checkNoRestart(const InternalServerDescriptorPtr & desc)2497 ServerI::checkNoRestart(const InternalServerDescriptorPtr& desc)
2498 {
2499 assert(_desc);
2500
2501 if(_desc->sessionId != desc->sessionId)
2502 {
2503 throw DeploymentException("server allocated by another session");
2504 }
2505
2506 if(descriptorUpdated(_desc, desc, true)) // true = ignore properties
2507 {
2508 throw DeploymentException("update requires server to be stopped");
2509 }
2510 }
2511
2512 #ifndef _WIN32
2513 void
checkAndUpdateUser(const InternalServerDescriptorPtr & desc,bool update)2514 ServerI::checkAndUpdateUser(const InternalServerDescriptorPtr& desc, bool update)
2515 #else
2516 void
2517 ServerI::checkAndUpdateUser(const InternalServerDescriptorPtr& desc, bool /*update*/)
2518 #endif
2519 {
2520 #ifndef _WIN32
2521 uid_t uid = getuid();
2522 uid_t gid = getgid();
2523 #endif
2524
2525 //
2526 // Don't change the user if the server has the session activation
2527 // mode and if it's not currently owned by a session.
2528 //
2529 string user;
2530 if(desc->activation != "session" || !desc->sessionId.empty())
2531 {
2532 user = desc->user;
2533 #ifndef _WIN32
2534 //
2535 // Check if the node is running as root, if that's the case we
2536 // make sure that a user is set for the process.
2537 //
2538 if(uid == 0 && user.empty())
2539 {
2540 //
2541 // If no user is configured and if this server is owned by
2542 // a session we set the user to the session id, otherwise
2543 // we set it to "nobody".
2544 //
2545 user = !desc->sessionId.empty() ? desc->sessionId : "nobody";
2546 }
2547 #endif
2548 }
2549
2550 if(!user.empty())
2551 {
2552 UserAccountMapperPrx mapper = _node->getUserAccountMapper();
2553 if(mapper)
2554 {
2555 try
2556 {
2557 user = mapper->getUserAccount(user);
2558 }
2559 catch(const UserAccountNotFoundException&)
2560 {
2561 throw runtime_error("couldn't find user account for user `" + user + "'");
2562 }
2563 catch(const Ice::LocalException& ex)
2564 {
2565 ostringstream os;
2566 os << "unexpected exception while trying to find user account for user `" << user << "':\n" << ex;
2567 throw runtime_error(os.str());
2568 }
2569 }
2570
2571 #ifdef _WIN32
2572 //
2573 // Windows doesn't support running processes under another
2574 // account (at least not easily, see the CreateProcessAsUser
2575 // documentation). So if a user is specified, we just check
2576 // that the node is running under the same user account as the
2577 // one which is specified.
2578 //
2579 vector<char> buf(256);
2580 buf.resize(256);
2581 DWORD size = static_cast<DWORD>(buf.size());
2582 bool success = GetUserName(&buf[0], &size);
2583 if(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2584 {
2585 buf.resize(size);
2586 success = GetUserName(&buf[0], &size);
2587 }
2588 if(!success)
2589 {
2590 throw Ice::SyscallException(__FILE__, __LINE__, IceInternal::getSystemErrno());
2591 }
2592 if(user != string(&buf[0]))
2593 {
2594 throw runtime_error("couldn't load server under user account `" + user + "': feature not supported on Windows");
2595 }
2596 }
2597 #else
2598 //
2599 // Get the uid/gid associated with the given user.
2600 //
2601 struct passwd pwbuf;
2602 int sz = sysconf(_SC_GETPW_R_SIZE_MAX);
2603 if(sz == -1)
2604 {
2605 sz = 4096;
2606 }
2607 vector<char> buffer(sz);
2608 struct passwd *pw;
2609 int err = getpwnam_r(user.c_str(), &pwbuf, &buffer[0], buffer.size(), &pw);
2610 while(err == ERANGE && buffer.size() < 1024 * 1024) // Limit buffer to 1MB
2611 {
2612 buffer.resize(buffer.size() * 2);
2613 err = getpwnam_r(user.c_str(), &pwbuf, &buffer[0], buffer.size(), &pw);
2614 }
2615
2616 if(err != 0)
2617 {
2618 throw Ice::SyscallException(__FILE__, __LINE__, err);
2619 }
2620 else if(pw == 0)
2621 {
2622 throw runtime_error("unknown user account `" + user + "'");
2623 }
2624
2625 //
2626 // If the node isn't running as root and if the uid of the
2627 // configured user is different from the uid of the userr
2628 // running the node we throw, a regular user can't run a
2629 // process as another user.
2630 //
2631 if(uid != 0 && pw->pw_uid != uid)
2632 {
2633 throw runtime_error("node has insufficient privileges to load server under user account `" + user + "'");
2634 }
2635
2636 if(pw->pw_uid == 0 &&
2637 _node->getCommunicator()->getProperties()->getPropertyAsInt("IceGrid.Node.AllowRunningServersAsRoot") <= 0)
2638 {
2639 throw runtime_error("running server as `root' is not allowed");
2640 }
2641
2642 if(update)
2643 {
2644 _uid = pw->pw_uid;
2645 _gid = pw->pw_gid;
2646 }
2647 }
2648 else if(update)
2649 {
2650 _uid = uid;
2651 _gid = gid;
2652 }
2653 #endif
2654 }
2655
2656 void
updateRevision(const string & uuid,int revision)2657 ServerI::updateRevision(const string& uuid, int revision)
2658 {
2659 _desc->uuid = uuid;
2660 _desc->revision = revision;
2661
2662 if(_load)
2663 {
2664 _load->getInternalServerDescriptor()->uuid = uuid;
2665 _load->getInternalServerDescriptor()->revision = revision;
2666 }
2667
2668 string idFilePath = _serverDir + "/revision";
2669 ofstream os(IceUtilInternal::streamFilename(idFilePath).c_str()); // idFilePath is a UTF-8 string
2670 if(os.good())
2671 {
2672 os << "#" << endl;
2673 os << "# This server belongs to the application `" << _desc->application << "'" << endl;
2674 os << "#" << endl;
2675 os << "uuid: " << _desc->uuid << endl;
2676 os << "revision: " << _desc->revision << endl;
2677 }
2678 }
2679
2680 void
updateRuntimePropertiesCallback(const InternalServerDescriptorPtr & desc)2681 ServerI::updateRuntimePropertiesCallback(const InternalServerDescriptorPtr& desc)
2682 {
2683 Lock sync(*this);
2684 if(_state != Active || !_load)
2685 {
2686 return;
2687 }
2688
2689 if(_load->finishRuntimePropertiesUpdate(desc, _process))
2690 {
2691 AdapterPrxDict adapters;
2692 for(ServerAdapterDict::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p)
2693 {
2694 adapters.insert(make_pair(p->first, p->second->getProxy()));
2695 }
2696 _load->finished(_this, adapters, _activationTimeout, _deactivationTimeout);
2697 }
2698 }
2699
2700 void
updateRuntimePropertiesCallback(const Ice::Exception & ex,const InternalServerDescriptorPtr & desc)2701 ServerI::updateRuntimePropertiesCallback(const Ice::Exception& ex, const InternalServerDescriptorPtr& desc)
2702 {
2703 Lock sync(*this);
2704 if(_state != Active || !_load)
2705 {
2706 return;
2707 }
2708
2709 if(_load->finishRuntimePropertiesUpdate(desc, _process))
2710 {
2711 _load->failed(ex);
2712 }
2713 }
2714
2715 bool
checkActivation()2716 ServerI::checkActivation()
2717 {
2718 //assert(locked());
2719 if(_state == ServerI::WaitForActivation || _state == ServerI::ActivationTimeout)
2720 {
2721 //
2722 // Mark the server as active if the server process proxy is registered (or it's not expecting
2723 // one to be registered) and if all the server lifetime adapters have been activated.
2724 //
2725 if((!_desc->processRegistered || _process) &&
2726 includes(_activatedAdapters.begin(), _activatedAdapters.end(),
2727 _serverLifetimeAdapters.begin(), _serverLifetimeAdapters.end()))
2728 {
2729 setStateNoSync(ServerI::Active);
2730 return true;
2731 }
2732 }
2733 return false;
2734 }
2735
2736 void
setState(InternalServerState st,const std::string & reason)2737 ServerI::setState(InternalServerState st, const std::string& reason)
2738 {
2739 ServerCommandPtr command;
2740 {
2741 Lock sync(*this);
2742 setStateNoSync(st, reason);
2743 command = nextCommand();
2744 }
2745 if(command)
2746 {
2747 command->execute();
2748 }
2749 }
2750
2751 ServerCommandPtr
nextCommand()2752 ServerI::nextCommand()
2753 {
2754 ServerCommandPtr command;
2755 if(_stop && _stop->canExecute(_state))
2756 {
2757 command = _stop;
2758 }
2759 else if(_destroy && _destroy->canExecute(_state))
2760 {
2761 command = _destroy;
2762 }
2763 else if(_load && _load->canExecute(_state))
2764 {
2765 command = _load;
2766 }
2767 else if(_patch && _patch->canExecute(_state))
2768 {
2769 command = _patch;
2770 }
2771 else if(_start && _start->canExecute(_state))
2772 {
2773 command = _start;
2774 }
2775 if(command)
2776 {
2777 setStateNoSync(command->nextState());
2778 }
2779 return command;
2780 }
2781
2782 void
setStateNoSync(InternalServerState st,const std::string & reason)2783 ServerI::setStateNoSync(InternalServerState st, const std::string& reason)
2784 {
2785 //
2786 // Ensure that the given state can be switched to.
2787 //
2788 switch(st)
2789 {
2790 case Inactive:
2791 break;
2792 case Patching:
2793 assert(_patch && _patch->canExecute(_state));
2794 break;
2795 case Loading:
2796 assert(_load && _load->canExecute(_state));
2797 break;
2798 case Activating:
2799 assert(_start && _start->canExecute(_state));
2800 break;
2801 case WaitForActivation:
2802 assert(_state == Activating);
2803 break;
2804 case ActivationTimeout:
2805 assert(_state == WaitForActivation);
2806 break;
2807 case Active:
2808 assert(_state == WaitForActivation || _state == ActivationTimeout);
2809 break;
2810 case Deactivating:
2811 //assert(_stop && _stop->canExecute(_state));
2812 break;
2813 case DeactivatingWaitForProcess:
2814 assert(_state == Deactivating);
2815 break;
2816 case Destroying:
2817 assert(_state == Inactive && _destroy && _destroy->canExecute(_state));
2818 break;
2819 case Destroyed:
2820 assert(_destroy);
2821 break;
2822 }
2823
2824 //
2825 // Change the current state.
2826 //
2827 InternalServerState previous = _state;
2828 _state = st;
2829
2830 //
2831 // Check if some commands are done.
2832 //
2833 bool loadFailure = false;
2834 switch(_state)
2835 {
2836 case Inactive:
2837 if(previous == Loading)
2838 {
2839 _load = 0;
2840 }
2841 if(previous == Patching)
2842 {
2843 _patch = 0;
2844 }
2845 if(_stop)
2846 {
2847 _stop->finished();
2848 _stop = 0;
2849 }
2850 break;
2851 case Active:
2852 if(_start)
2853 {
2854 _start->finished();
2855 _start = 0;
2856 }
2857 break;
2858 case ActivationTimeout:
2859 if(_start)
2860 {
2861 _start->failed(reason);
2862 _start = 0;
2863 }
2864 break;
2865 case Deactivating:
2866 if(_start)
2867 {
2868 _start->failed(reason.empty() ? string("The server is being deactivated.") : reason);
2869 _start = 0;
2870 }
2871 break;
2872 case Destroying:
2873 loadFailure = _destroy->loadFailure();
2874 if(_patch)
2875 {
2876 _patch->destroyed();
2877 _patch = 0;
2878 }
2879 if(_load)
2880 {
2881 _load->failed(DeploymentException("The server is being destroyed."));
2882 _load = 0;
2883 }
2884 if(_start)
2885 {
2886 _start->failed("The server is being destroyed.");
2887 _start = 0;
2888 }
2889 if(_stop)
2890 {
2891 _stop->failed("The server is being destroyed.");
2892 _stop = 0;
2893 }
2894 break;
2895 case Destroyed:
2896 if(_destroy)
2897 {
2898 loadFailure = _destroy->loadFailure();
2899 _destroy->finished();
2900 _destroy = 0;
2901 }
2902 notifyAll(); // for getProperties()
2903 break;
2904 default:
2905 break;
2906 }
2907
2908 if(_timerTask)
2909 {
2910 _node->getTimer()->cancel(_timerTask);
2911 _timerTask = 0;
2912 }
2913
2914 if(_state == Destroyed && !_load)
2915 {
2916 //
2917 // If the server is destroyed and there's no load command, we
2918 // remove the servant from the ASM.
2919 //
2920 try
2921 {
2922 _node->getAdapter()->remove(_this->ice_getIdentity());
2923 }
2924 catch(const Ice::ObjectAdapterDeactivatedException&)
2925 {
2926 // IGNORE
2927 }
2928 _desc = 0;
2929 }
2930 else if(_state == Inactive)
2931 {
2932 if(_activation == Always)
2933 {
2934 assert(!_timerTask);
2935 _timerTask = new DelayedStart(this, _node->getTraceLevels());
2936 try
2937 {
2938 _node->getTimer()->schedule(_timerTask, IceUtil::Time::milliSeconds(500));
2939 }
2940 catch(const IceUtil::Exception&)
2941 {
2942 // Ignore, timer is destroyed because node is shutting down.
2943 }
2944 }
2945 else if(_activation == Disabled && _disableOnFailure > 0 && _failureTime != IceUtil::Time())
2946 {
2947 //
2948 // If the server was disabled because it failed, we
2949 // schedule a callback to re-enable it. We add 500ms to
2950 // the disable on failure duration to make sure that the
2951 // server will be ready to be reactivated when the
2952 // callback is executed.
2953 //
2954 assert(!_timerTask);
2955 _timerTask = new DelayedStart(this, _node->getTraceLevels());
2956 try
2957 {
2958 IceUtil::Time now = IceUtil::Time::now(IceUtil::Time::Monotonic);
2959 if(now - _failureTime < IceUtil::Time::seconds(_disableOnFailure))
2960 {
2961 _node->getTimer()->schedule(_timerTask,
2962 IceUtil::Time::seconds(_disableOnFailure) - now + _failureTime +
2963 IceUtil::Time::milliSeconds(500));
2964 }
2965 else
2966 {
2967 _node->getTimer()->schedule(_timerTask, IceUtil::Time::milliSeconds(500));
2968 }
2969 }
2970 catch(const IceUtil::Exception&)
2971 {
2972 // Ignore, timer is destroyed because node is shutting down.
2973 }
2974 }
2975 }
2976 else if(_state == Active && _load)
2977 {
2978 //
2979 // If there's a pending load command, it's time to update the
2980 // runtime properties of the server now that it's active.
2981 //
2982 _load->startRuntimePropertiesUpdate(_process);
2983 }
2984
2985 //
2986 // Don't send the server update if the state didn't change or if
2987 // the server couldn't be forked. If the server is destroyed, we
2988 // also check if it's the result of a load failure. If that's the
2989 // case we don't send an update because the server was never
2990 // actually loaded.
2991 //
2992 if(toServerState(previous) != toServerState(_state) &&
2993 !(previous == Inactive && _state == Deactivating) &&
2994 !loadFailure)
2995 {
2996 _node->observerUpdateServer(getDynamicInfo());
2997 }
2998
2999 if(_node->getTraceLevels()->server > 1)
3000 {
3001 if(_state == ServerI::Active)
3002 {
3003 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3004 out << "changed server `" << _id << "' state to `Active'";
3005 }
3006 else if(_state == ServerI::Inactive)
3007 {
3008 if(_node->getTraceLevels()->server != 2 && !(previous == ServerI::Loading || previous == ServerI::Patching))
3009 {
3010 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3011 out << "changed server `" << _id << "' state to `Inactive'";
3012 }
3013 }
3014 else if(_state == ServerI::Destroyed)
3015 {
3016 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3017 out << "changed server `" << _id << "' state to `Destroyed'";
3018 }
3019 else if(_node->getTraceLevels()->server > 2)
3020 {
3021 if(_state == ServerI::WaitForActivation)
3022 {
3023 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3024 out << "changed server `" << _id << "' state to `WaitForActivation'";
3025 }
3026 else if(_state == ServerI::ActivationTimeout)
3027 {
3028 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3029 out << "changed server `" << _id << "' state to `ActivationTimeout'";
3030 }
3031 else if(_state == ServerI::Activating)
3032 {
3033 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3034 out << "changed server `" << _id << "' state to `Activating'";
3035 }
3036 else if(_state == ServerI::Deactivating)
3037 {
3038 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3039 out << "changed server `" << _id << "' state to `Deactivating'";
3040 }
3041 else if(_state == ServerI::DeactivatingWaitForProcess)
3042 {
3043 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3044 out << "changed server `" << _id << "' state to `DeactivatingWaitForProcess'";
3045 }
3046 else if(_state == ServerI::Destroying)
3047 {
3048 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3049 out << "changed server `" << _id << "' state to `Destroying'";
3050 }
3051 else if(_state == ServerI::Loading)
3052 {
3053 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3054 out << "changed server `" << _id << "' state to `Loading'";
3055 }
3056 else if(_state == ServerI::Patching)
3057 {
3058 Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat);
3059 out << "changed server `" << _id << "' state to `Loading'";
3060 }
3061 }
3062 }
3063 }
3064
3065 ServerState
toServerState(InternalServerState st) const3066 ServerI::toServerState(InternalServerState st) const
3067 {
3068 switch(st)
3069 {
3070 case ServerI::Inactive:
3071 case ServerI::Activating:
3072 case ServerI::Patching:
3073 case ServerI::Loading:
3074 return IceGrid::Inactive;
3075 case ServerI::WaitForActivation:
3076 return IceGrid::Activating;
3077 case ServerI::ActivationTimeout:
3078 return IceGrid::ActivationTimedOut;
3079 case ServerI::Active:
3080 return IceGrid::Active;
3081 case ServerI::Deactivating:
3082 case ServerI::DeactivatingWaitForProcess:
3083 return IceGrid::Deactivating;
3084 case ServerI::Destroying:
3085 return IceGrid::Destroying;
3086 case ServerI::Destroyed:
3087 return IceGrid::Destroyed;
3088 default:
3089 assert(false);
3090 return IceGrid::Destroyed;
3091 }
3092 }
3093
3094 ServerI::ServerActivation
toServerActivation(const string & activation) const3095 ServerI::toServerActivation(const string& activation) const
3096 {
3097 if(activation == "on-demand")
3098 {
3099 return OnDemand;
3100 }
3101 else if(activation == "session")
3102 {
3103 return Session;
3104 }
3105 else if(activation == "always")
3106 {
3107 return Always;
3108 }
3109 else if(activation == "manual" || activation.empty())
3110 {
3111 return Manual;
3112 }
3113 else
3114 {
3115 Ice::Warning out(_node->getTraceLevels()->logger);
3116 out << "unknown activation mode `" << activation << "' for server `" << _id << "'";
3117 return Manual;
3118 }
3119 }
3120
3121 ServerDynamicInfo
getDynamicInfo() const3122 ServerI::getDynamicInfo() const
3123 {
3124 ServerDynamicInfo descriptor;
3125 descriptor.id = _id;
3126 descriptor.state = toServerState(_state);
3127
3128 //
3129 // NOTE: this must be done only for the active state. Otherwise, we could get a
3130 // deadlock since getPid() will lock the activator and since this method might
3131 // be called from the activator locked.
3132 //
3133 descriptor.pid = _pid;
3134 descriptor.enabled = _activation != Disabled;
3135 return descriptor;
3136 }
3137
3138 string
getFilePath(const string & filename) const3139 ServerI::getFilePath(const string& filename) const
3140 {
3141 if(filename == "stderr")
3142 {
3143 if(_stdErrFile.empty())
3144 {
3145 throw FileNotAvailableException("Ice.StdErr configuration property is not set");
3146 }
3147 return _stdErrFile;
3148 }
3149 else if(filename == "stdout")
3150 {
3151 if(_stdOutFile.empty())
3152 {
3153 throw FileNotAvailableException("Ice.StdOut configuration property is not set");
3154 }
3155 return _stdOutFile;
3156 }
3157 else if(!filename.empty() && filename[0] == '#')
3158 {
3159 string path = IcePatch2Internal::simplify(filename.substr(1));
3160 if(!IceUtilInternal::isAbsolutePath(path))
3161 {
3162 path = _node->getPlatformInfo().getCwd() + "/" + path;
3163 }
3164 if(find(_logs.begin(), _logs.end(), path) == _logs.end())
3165 {
3166 throw FileNotAvailableException("unknown log file `" + path + "'");
3167 }
3168 return path;
3169 }
3170 else
3171 {
3172 throw FileNotAvailableException("unknown file");
3173 }
3174 }
3175
3176 PropertyDescriptorSeqDict
getProperties(const InternalServerDescriptorPtr & desc)3177 ServerI::getProperties(const InternalServerDescriptorPtr& desc)
3178 {
3179 //
3180 // Copy the descriptor properties.
3181 //
3182 PropertyDescriptorSeqDict propDict = desc->properties;
3183 PropertyDescriptorSeq& props = propDict["config"];
3184
3185 //
3186 // Cache the path of the stderr/stdout file, first check if the
3187 // node OutputDir property is set and then we check the server
3188 // configuration file for the Ice.StdErr and Ice.StdOut
3189 // properties.
3190 //
3191 string stdErrFile = getProperty(props, "Ice.StdErr");
3192 string stdOutFile = getProperty(props, "Ice.StdOut");
3193 string outputDir = _node->getOutputDir();
3194 if(!outputDir.empty())
3195 {
3196 if(stdErrFile.empty())
3197 {
3198 stdErrFile = outputDir + "/" + _id + (_node->getRedirectErrToOut() ? ".out" : ".err");
3199 props.push_back(createProperty("Ice.StdErr", stdErrFile));
3200 }
3201 if(stdOutFile.empty())
3202 {
3203 stdOutFile = outputDir + "/" + _id + ".out";
3204 props.push_back(createProperty("Ice.StdOut", stdOutFile));
3205 }
3206 }
3207
3208 //
3209 // Add the locator proxy property and the node properties override
3210 //
3211 {
3212 const PropertyDescriptorSeq& overrides = _node->getPropertiesOverride();
3213 for(PropertyDescriptorSeqDict::iterator p = propDict.begin(); p != propDict.end(); ++p)
3214 {
3215 if(getProperty(p->second, "Ice.Default.Locator").empty())
3216 {
3217 Ice::PropertiesPtr properties = _node->getCommunicator()->getProperties();
3218
3219 string locator = properties->getProperty("Ice.Default.Locator");
3220 if(!locator.empty())
3221 {
3222 p->second.push_back(createProperty("Ice.Default.Locator", locator));
3223 }
3224
3225 string discoveryPlugin = properties->getProperty("Ice.Plugin.IceLocatorDiscovery");
3226 if(!discoveryPlugin.empty())
3227 {
3228 p->second.push_back(createProperty("Ice.Plugin.IceLocatorDiscovery", discoveryPlugin));
3229 p->second.push_back(createProperty("IceLocatorDiscovery.InstanceName", _node->getInstanceName()));
3230 }
3231 }
3232
3233 if(!overrides.empty())
3234 {
3235 p->second.push_back(createProperty("# Node properties override"));
3236 p->second.insert(p->second.end(), overrides.begin(), overrides.end());
3237 }
3238 }
3239 }
3240
3241 return propDict;
3242 }
3243