diff options
author | Benoit Foucher <benoit@zeroc.com> | 2012-08-30 14:43:15 +0200 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2012-08-30 14:43:15 +0200 |
commit | aab12cf1719b425b5a2c571b8938d47cdd71d151 (patch) | |
tree | 876561b05764721306eb8629883e7b0b9cbbc99a /cpp/src | |
parent | minor g++ warning (diff) | |
download | ice-aab12cf1719b425b5a2c571b8938d47cdd71d151.tar.bz2 ice-aab12cf1719b425b5a2c571b8938d47cdd71d151.tar.xz ice-aab12cf1719b425b5a2c571b8938d47cdd71d151.zip |
ICE-4774: Merged skype_props enhancement
Diffstat (limited to 'cpp/src')
31 files changed, 1678 insertions, 561 deletions
diff --git a/cpp/src/Ice/CommunicatorI.cpp b/cpp/src/Ice/CommunicatorI.cpp index 25762041b06..2acb01718bb 100644 --- a/cpp/src/Ice/CommunicatorI.cpp +++ b/cpp/src/Ice/CommunicatorI.cpp @@ -384,6 +384,12 @@ Ice::CommunicatorI::removeAdminFacet(const string& facet) return _instance->removeAdminFacet(facet); } +Ice::ObjectPtr +Ice::CommunicatorI::findAdminFacet(const string& facet) +{ + return _instance->findAdminFacet(facet); +} + Ice::CommunicatorI::CommunicatorI(const InitializationData& initData) { __setNoDelete(true); diff --git a/cpp/src/Ice/CommunicatorI.h b/cpp/src/Ice/CommunicatorI.h index d9628478707..384a6a7936c 100644 --- a/cpp/src/Ice/CommunicatorI.h +++ b/cpp/src/Ice/CommunicatorI.h @@ -79,6 +79,7 @@ public: virtual ObjectPrx getAdmin() const; virtual void addAdminFacet(const ObjectPtr&, const std::string&); virtual ObjectPtr removeAdminFacet(const std::string&); + virtual ObjectPtr findAdminFacet(const std::string&); private: diff --git a/cpp/src/Ice/Instance.cpp b/cpp/src/Ice/Instance.cpp index 5dda22e333c..c062c5a7671 100644 --- a/cpp/src/Ice/Instance.cpp +++ b/cpp/src/Ice/Instance.cpp @@ -25,6 +25,7 @@ #include <Ice/ObjectAdapterFactory.h> #include <Ice/Exception.h> #include <Ice/PropertiesI.h> +#include <Ice/PropertiesAdminI.h> #include <Ice/LoggerI.h> #include <Ice/Network.h> #include <Ice/EndpointFactoryManager.h> @@ -724,6 +725,35 @@ IceInternal::Instance::removeAdminFacet(const string& facet) { result = _adminAdapter->removeFacet(_adminIdentity, facet); } + + return result; +} + +Ice::ObjectPtr +IceInternal::Instance::findAdminFacet(const string& facet) +{ + IceUtil::RecMutex::Lock sync(*this); + + if(_state == StateDestroyed) + { + throw CommunicatorDestroyedException(__FILE__, __LINE__); + } + + ObjectPtr result; + + if(_adminAdapter == 0 || (!_adminFacetFilter.empty() && _adminFacetFilter.find(facet) == _adminFacetFilter.end())) + { + FacetMap::iterator p = _adminFacets.find(facet); + if(p != _adminFacets.end()) + { + result = p->second; + } + } + else + { + result = _adminAdapter->findFacet(_adminIdentity, facet); + } + return result; } @@ -1074,7 +1104,9 @@ IceInternal::Instance::Instance(const CommunicatorPtr& communicator, const Initi _adminFacetFilter.insert(facetSeq.begin(), facetSeq.end()); } - _adminFacets.insert(FacetMap::value_type("Properties", new PropertiesAdminI(_initData.properties))); + _adminFacets.insert( + FacetMap::value_type("Properties", + new PropertiesAdminI("Properties", _initData.properties, _initData.logger))); _adminFacets.insert(FacetMap::value_type("Process", new ProcessI(communicator))); IceMX::MetricsAdminIPtr admin = new IceMX::MetricsAdminI(_initData.properties); _adminFacets.insert(FacetMap::value_type("MetricsAdmin", admin)); diff --git a/cpp/src/Ice/Instance.h b/cpp/src/Ice/Instance.h index 1cda82f3608..df97e4390d0 100644 --- a/cpp/src/Ice/Instance.h +++ b/cpp/src/Ice/Instance.h @@ -85,6 +85,7 @@ public: Ice::ObjectPrx getAdmin(); void addAdminFacet(const Ice::ObjectPtr&, const std::string&); Ice::ObjectPtr removeAdminFacet(const std::string&); + Ice::ObjectPtr findAdminFacet(const std::string&); const Ice::ImplicitContextIPtr& getImplicitContext() const { diff --git a/cpp/src/Ice/Makefile b/cpp/src/Ice/Makefile index 4aea8c9f907..54110fbf2fe 100644 --- a/cpp/src/Ice/Makefile +++ b/cpp/src/Ice/Makefile @@ -85,6 +85,7 @@ OBJS = Acceptor.o \ PluginManagerI.o \ Plugin.o \ Process.o \ + PropertiesAdminI.o \ PropertiesI.o \ Properties.o \ PropertyNames.o \ diff --git a/cpp/src/Ice/Makefile.mak b/cpp/src/Ice/Makefile.mak index e07cc6833bc..a2b12348f0e 100644 --- a/cpp/src/Ice/Makefile.mak +++ b/cpp/src/Ice/Makefile.mak @@ -79,6 +79,7 @@ OBJS = Acceptor.obj \ PluginManagerI.obj \
Plugin.obj \
Process.obj \
+ PropertiesAdminI.obj \
PropertiesI.obj \
Properties.obj \
PropertyNames.obj \
diff --git a/cpp/src/Ice/PropertiesAdminI.cpp b/cpp/src/Ice/PropertiesAdminI.cpp new file mode 100644 index 00000000000..fc929bb959a --- /dev/null +++ b/cpp/src/Ice/PropertiesAdminI.cpp @@ -0,0 +1,187 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/DisableWarnings.h> +#include <Ice/PropertiesAdminI.h> +#include <Ice/Logger.h> +#include <Ice/LoggerUtil.h> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +Ice::PropertiesAdminI::PropertiesAdminI(const string& name, const PropertiesPtr& properties, const LoggerPtr& logger) : + _name(name), _properties(properties), _logger(logger) +{ +} + +string +Ice::PropertiesAdminI::getProperty(const string& name, const Ice::Current&) +{ + IceUtil::Mutex::Lock sync(*this); + return _properties->getProperty(name); +} + +Ice::PropertyDict +Ice::PropertiesAdminI::getPropertiesForPrefix(const string& prefix, const Ice::Current&) +{ + IceUtil::Mutex::Lock sync(*this); + return _properties->getPropertiesForPrefix(prefix); +} + +void +Ice::PropertiesAdminI::setProperties_async(const AMD_PropertiesAdmin_setPropertiesPtr& cb, const PropertyDict& props, + const Ice::Current&) +{ + PropertyDict added, changed, removed; + PropertiesAdminUpdateCallbackPtr callback; + { + IceUtil::Mutex::Lock sync(*this); + + PropertyDict old = _properties->getPropertiesForPrefix(""); + PropertyDict::const_iterator p; + const int traceLevel = _properties->getPropertyAsInt("Ice.Trace.Admin.Properties"); + + // + // Compute the difference between the new property set and the existing property set: + // + // 1) Any properties in the new set that were not defined in the existing set. + // + // 2) Any properties that appear in both sets but with different values. + // + // 3) Any properties not present in the new set but present in the existing set. + // In other words, the property has been removed. + // + for(p = props.begin(); p != props.end(); ++p) + { + PropertyDict::iterator q = old.find(p->first); + if(q == old.end()) + { + if(!p->second.empty()) + { + // + // This property is new. + // + added.insert(*p); + } + } + else + { + if(p->second != q->second) + { + if(p->second.empty()) + { + // + // This property was removed. + // + removed.insert(*p); + } + else + { + // + // This property has changed. + // + changed.insert(*p); + } + } + } + } + + if(traceLevel > 0 && (!added.empty() || !changed.empty() || !removed.empty())) + { + Trace out(_logger, _name); + + out << "Summary of property changes"; + + if(!added.empty()) + { + out << "\nNew properties:"; + for(p = added.begin(); p != added.end(); ++p) + { + out << "\n " << p->first; + if(traceLevel > 1) + { + out << " = " << p->second; + } + } + } + + if(!changed.empty()) + { + out << "\nChanged properties:"; + for(p = changed.begin(); p != changed.end(); ++p) + { + out << "\n " << p->first; + if(traceLevel > 1) + { + out << " = " << p->second << " (old value = " << _properties->getProperty(p->first) << ")"; + } + } + } + + if(!removed.empty()) + { + out << "\nRemoved properties:"; + for(p = removed.begin(); p != removed.end(); ++p) + { + out << "\n " << p->first; + } + } + } + + // + // Update the property set. + // + + for(p = added.begin(); p != added.end(); ++p) + { + _properties->setProperty(p->first, p->second); + } + + for(p = changed.begin(); p != changed.end(); ++p) + { + _properties->setProperty(p->first, p->second); + } + + for(p = removed.begin(); p != removed.end(); ++p) + { + _properties->setProperty(p->first, ""); + } + + callback = _updateCallback; + } + + // + // Send the response now so that we do not block the client during the call to the update callback. + // + cb->ice_response(); + + if(callback) + { + PropertyDict changes = added; + changes.insert(changed.begin(), changed.end()); + changes.insert(removed.begin(), removed.end()); + + try + { + callback->updated(changes); + } + catch(...) + { + // Ignore. + } + } +} + +void +Ice::PropertiesAdminI::setUpdateCallback(const PropertiesAdminUpdateCallbackPtr& cb) +{ + IceUtil::Mutex::Lock sync(*this); + _updateCallback = cb; +} diff --git a/cpp/src/Ice/PropertiesAdminI.h b/cpp/src/Ice/PropertiesAdminI.h new file mode 100644 index 00000000000..2ddf420aa3e --- /dev/null +++ b/cpp/src/Ice/PropertiesAdminI.h @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef ICE_PROPERTIES_ADMIN_I_H +#define ICE_PROPERTIES_ADMIN_I_H + +#include <IceUtil/Mutex.h> +#include <Ice/PropertiesAdmin.h> +#include <Ice/LoggerF.h> + +namespace Ice +{ + +class ICE_API PropertiesAdminI : public PropertiesAdmin, public NativePropertiesAdmin, private IceUtil::Mutex +{ +public: + + PropertiesAdminI(const std::string&, const PropertiesPtr&, const LoggerPtr&); + + virtual std::string getProperty(const std::string&, const Current&); + virtual PropertyDict getPropertiesForPrefix(const std::string&, const Current&); + virtual void setProperties_async(const AMD_PropertiesAdmin_setPropertiesPtr&, const PropertyDict&, const Current&); + + virtual void setUpdateCallback(const PropertiesAdminUpdateCallbackPtr&); + +private: + + const std::string _name; + const PropertiesPtr _properties; + const LoggerPtr _logger; + PropertiesAdminUpdateCallbackPtr _updateCallback; +}; + +} + +#endif diff --git a/cpp/src/Ice/PropertiesI.cpp b/cpp/src/Ice/PropertiesI.cpp index 9bde5157184..1c4f2670597 100644 --- a/cpp/src/Ice/PropertiesI.cpp +++ b/cpp/src/Ice/PropertiesI.cpp @@ -774,26 +774,3 @@ Ice::PropertiesI::loadConfig() PropertyValue pv(value, true); _properties["Ice.Config"] = pv; } - - -// -// PropertiesAdminI -// - - -Ice::PropertiesAdminI::PropertiesAdminI(const PropertiesPtr& properties) : - _properties(properties) -{ -} - -string -Ice::PropertiesAdminI::getProperty(const string& name, const Ice::Current&) -{ - return _properties->getProperty(name); -} - -Ice::PropertyDict -Ice::PropertiesAdminI::getPropertiesForPrefix(const string& prefix, const Ice::Current&) -{ - return _properties->getPropertiesForPrefix(prefix); -} diff --git a/cpp/src/Ice/PropertiesI.h b/cpp/src/Ice/PropertiesI.h index ee6df06c1bb..a54b042cff2 100644 --- a/cpp/src/Ice/PropertiesI.h +++ b/cpp/src/Ice/PropertiesI.h @@ -72,19 +72,4 @@ private: const StringConverterPtr _converter; }; - -class PropertiesAdminI : public PropertiesAdmin -{ -public: - - PropertiesAdminI(const PropertiesPtr&); - - virtual std::string getProperty(const std::string&, const Current&); - virtual PropertyDict getPropertiesForPrefix(const std::string&, const Current&); - -private: - - const PropertiesPtr _properties; -}; - } diff --git a/cpp/src/Ice/PropertyNames.cpp b/cpp/src/Ice/PropertyNames.cpp index b1de65c529d..b9e7b8cd97b 100644 --- a/cpp/src/Ice/PropertyNames.cpp +++ b/cpp/src/Ice/PropertyNames.cpp @@ -8,7 +8,7 @@ // ********************************************************************** // -// Generated by makeprops.py from file ./config/PropertyNames.xml, Fri Aug 10 10:27:32 2012 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Aug 30 14:36:00 2012 // IMPORTANT: Do not edit this file -- any edits made here will be lost! @@ -137,6 +137,7 @@ const IceInternal::Property IcePropsData[] = IceInternal::Property("Ice.ThreadPool.Server.ThreadIdleTime", false, 0), IceInternal::Property("Ice.ThreadPool.Server.ThreadPriority", false, 0), IceInternal::Property("Ice.ThreadPriority", false, 0), + IceInternal::Property("Ice.Trace.Admin.Properties", false, 0), IceInternal::Property("Ice.Trace.GC", false, 0), IceInternal::Property("Ice.Trace.Location", true, "Ice.Trace.Locator"), IceInternal::Property("Ice.Trace.Locator", false, 0), diff --git a/cpp/src/Ice/PropertyNames.h b/cpp/src/Ice/PropertyNames.h index ce4a7927dcb..ecb560f6943 100644 --- a/cpp/src/Ice/PropertyNames.h +++ b/cpp/src/Ice/PropertyNames.h @@ -8,7 +8,7 @@ // ********************************************************************** // -// Generated by makeprops.py from file ./config/PropertyNames.xml, Fri Aug 10 10:27:32 2012 +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Aug 30 14:36:00 2012 // IMPORTANT: Do not edit this file -- any edits made here will be lost! diff --git a/cpp/src/IceBox/ServiceManagerI.cpp b/cpp/src/IceBox/ServiceManagerI.cpp index f91e9cd8da2..ce763ba0844 100644 --- a/cpp/src/IceBox/ServiceManagerI.cpp +++ b/cpp/src/IceBox/ServiceManagerI.cpp @@ -14,6 +14,7 @@ #include <Ice/SliceChecksums.h> #include <Ice/Initialize.h> #include <Ice/Instance.h> +#include <Ice/PropertiesAdminI.h> #include <IceBox/ServiceManagerI.h> using namespace Ice; @@ -25,30 +26,6 @@ typedef IceBox::Service* (*SERVICE_FACTORY)(CommunicatorPtr); namespace { -class PropertiesAdminI : public PropertiesAdmin -{ -public: - - PropertiesAdminI(const PropertiesPtr& properties) : - _properties(properties) - { - } - - virtual string getProperty(const string& name, const Current&) - { - return _properties->getProperty(name); - } - - virtual PropertyDict getPropertiesForPrefix(const string& prefix, const Current&) - { - return _properties->getPropertiesForPrefix(prefix); - } - -private: - - const PropertiesPtr _properties; -}; - struct StartServiceInfo { StartServiceInfo(const std::string& service, const std::string& value, const Ice::StringSeq& serverArgs) @@ -65,8 +42,8 @@ struct StartServiceInfo } catch(const IceUtilInternal::BadOptException& ex) { - PluginInitializationException e(__FILE__, __LINE__); - e.reason = "invalid arguments for service `" + name + "':\n" + ex.reason; + FailureException e(__FILE__, __LINE__); + e.reason = "ServiceManager: invalid arguments for service `" + name + "':\n" + ex.reason; throw e; } @@ -157,7 +134,7 @@ IceBox::ServiceManagerI::startService(const string& name, const Current&) info.service->start(name, info.communicator == 0 ? _sharedCommunicator : info.communicator, info.args); started = true; } - catch(const Ice::Exception& ex) + catch(const Exception& ex) { Warning out(_logger); out << "ServiceManager: exception in start for service " << info.name << ":\n"; @@ -235,7 +212,7 @@ IceBox::ServiceManagerI::stopService(const string& name, const Current&) info.service->stop(); stopped = true; } - catch(const Ice::Exception& ex) + catch(const Exception& ex) { Warning out(_logger); out << "ServiceManager: exception while stopping service " << info.name << ":\n"; @@ -276,7 +253,7 @@ IceBox::ServiceManagerI::stopService(const string& name, const Current&) } void -IceBox::ServiceManagerI::addObserver(const ServiceObserverPrx& observer, const Ice::Current&) +IceBox::ServiceManagerI::addObserver(const ServiceObserverPrx& observer, const Current&) { // // Null observers and duplicate registrations are ignored @@ -458,18 +435,6 @@ IceBox::ServiceManagerI::start() try { _communicator->addAdminFacet(this, "IceBox.ServiceManager"); - - // - // Add a Properties facet for each service - // - for(vector<ServiceInfo>::iterator r = _services.begin(); r != _services.end(); ++r) - { - const ServiceInfo& info = *r; - CommunicatorPtr communicator = info.communicator != 0 ? info.communicator : _sharedCommunicator; - _communicator->addAdminFacet(new PropertiesAdminI(communicator->getProperties()), - "IceBox.Service." + info.name + ".Properties"); - } - _communicator->getAdmin(); } catch(const ObjectAdapterDeactivatedException&) @@ -536,11 +501,6 @@ IceBox::ServiceManagerI::start(const string& service, const string& entryPoint, { IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); - ServiceInfo info; - info.name = service; - info.status = Stopped; - info.args = args; - // // Load the entry point. // @@ -559,57 +519,27 @@ IceBox::ServiceManagerI::start(const string& service, const string& entryPoint, throw ex; } + ServiceInfo info; + info.name = service; + info.status = Stopped; + info.args = args; + // - // Invoke the factory function. + // If Ice.UseSharedCommunicator.<name> is not defined, create + // a communicator for the service. The communicator inherits + // from the shared communicator properties. If it's defined + // add the service properties to the shared commnunicator + // property set. // - SERVICE_FACTORY factory = (SERVICE_FACTORY)sym; - try - { - info.service = factory(_communicator); - } - catch(const FailureException&) - { - throw; - } - catch(const Exception& ex) + Ice::CommunicatorPtr communicator; + if(_communicator->getProperties()->getPropertyAsInt("IceBox.UseSharedCommunicator." + service) > 0) { - ostringstream s; - s << "ServiceManager: exception in entry point `" + entryPoint + "' for service " << service << ":\n"; - s << ex; - - FailureException e(__FILE__, __LINE__); - e.reason = s.str(); - throw e; - } - catch(...) - { - ostringstream s; - s << "ServiceManager: unknown exception in entry point `" + entryPoint + "' for service " << service; - - FailureException e(__FILE__, __LINE__); - e.reason = s.str(); - throw e; + assert(_sharedCommunicator); + communicator = _sharedCommunicator; } - - // - // Invoke Service::start(). - // - try + else { - // - // If Ice.UseSharedCommunicator.<name> is not defined, create - // a communicator for the service. The communicator inherits - // from the shared communicator properties. If it's defined - // add the service properties to the shared commnunicator - // property set. - // - Ice::CommunicatorPtr communicator; - if(_communicator->getProperties()->getPropertyAsInt("IceBox.UseSharedCommunicator." + service) > 0) - { - assert(_sharedCommunicator); - communicator = _sharedCommunicator; - } - else + try { // // Create the service properties. We use the communicator properties as the default @@ -624,19 +554,19 @@ IceBox::ServiceManagerI::start(const string& service, const string& entryPoint, // read the service config file if it's specified with --Ice.Config. // initData.properties = createProperties(info.args, initData.properties); - + // // Next, parse the service "<service>.*" command line options (the Ice command // line options were parsed by the createProperties above) // info.args = initData.properties->parseCommandLineOptions(service, info.args); } - + // // Clone the logger to assign a new prefix. // initData.logger = _logger->cloneWithPrefix(initData.properties->getProperty("Ice.ProgramName")); - + // // Remaining command line options are passed to the communicator. This is // necessary for Ice plug-in properties (e.g.: IceSSL). @@ -644,15 +574,69 @@ IceBox::ServiceManagerI::start(const string& service, const string& entryPoint, info.communicator = initialize(info.args, initData); communicator = info.communicator; } + catch(const Exception& ex) + { + ostringstream s; + s << "ServiceManager: exception while starting service " << service << ":\n"; + s << ex; + FailureException e(__FILE__, __LINE__); + e.reason = s.str(); + throw e; + } + } + + try + { + // + // Add a PropertiesAdmin facet to the service manager's communicator that provides + // access to this service's property set. We do this prior to instantiating the + // service so that the service's constructor is able to access the facet (e.g., + // in case it wants to set a callback). + // + string facetName = "IceBox.Service." + info.name + ".Properties"; + _communicator->addAdminFacet( + new PropertiesAdminI(facetName, communicator->getProperties(), communicator->getLogger()), facetName); + + // + // Invoke the factory function. + // + SERVICE_FACTORY factory = (SERVICE_FACTORY)sym; + try + { + info.service = factory(_communicator); + } + catch(const FailureException&) + { + throw; + } + catch(const Exception& ex) + { + ostringstream s; + s << "ServiceManager: exception in entry point `" + entryPoint + "' for service " << info.name << ":\n"; + s << ex; + + FailureException e(__FILE__, __LINE__); + e.reason = s.str(); + throw e; + } + catch(...) + { + ostringstream s; + s << "ServiceManager: unknown exception in entry point `" + entryPoint + "' for service " << info.name; + + FailureException e(__FILE__, __LINE__); + e.reason = s.str(); + throw e; + } + // // Start the service. // try { - info.service->start(service, communicator, info.args); - info.status = Started; - + info.service->start(info.name, communicator, info.args); + // // There is no need to notify the observers since the 'start all' // (that indirectly calls this function) occurs before the creation of @@ -660,71 +644,61 @@ IceBox::ServiceManagerI::start(const string& service, const string& entryPoint, // object adapter (so before any observer can be registered) // } + catch(const FailureException&) + { + throw; + } + catch(const Exception& ex) + { + ostringstream s; + s << "ServiceManager: exception while starting service " << info.name << ":\n"; + s << ex; + + FailureException e(__FILE__, __LINE__); + e.reason = s.str(); + throw e; + } catch(...) { - if(info.communicator) - { - try - { - info.communicator->shutdown(); - info.communicator->waitForShutdown(); - } - catch(const Ice::CommunicatorDestroyedException&) - { - // - // Ignore, the service might have already destroyed - // the communicator for its own reasons. - // - } - catch(const Ice::Exception& ex) - { - Warning out(_logger); - out << "ServiceManager: exception while shutting down communicator for service " << service - << ":\n"; - out << ex; - } + ostringstream s; + s << "ServiceManager: unknown exception while starting service " << info.name; - try - { - info.communicator->destroy(); - info.communicator = 0; - } - catch(const Exception& ex) - { - Warning out(_logger); - out << "ServiceManager: exception while destroying communicator for service " << service - << ":\n"; - out << ex; - } - } - throw; + FailureException e(__FILE__, __LINE__); + e.reason = s.str(); + throw e; } info.library = library; + info.status = Started; _services.push_back(info); } - catch(const FailureException&) + catch(const ObjectAdapterDeactivatedException&) { - throw; + // + // Can be raised by addAdminFacet if the service manager communicator has been shut down. + // + if(info.communicator) + { + destroyServiceCommunicator(info.name, info.communicator); + } } - catch(const Exception& ex) + catch(const Exception&) { - ostringstream s; - s << "ServiceManager: exception while starting service " << service << ":\n"; - s << ex; + try + { + _communicator->removeAdminFacet("IceBox.Service." + info.name + ".Properties"); + } + catch(const LocalException&) + { + // Ignored + } - FailureException e(__FILE__, __LINE__); - e.reason = s.str(); - throw e; - } - catch(...) - { - ostringstream s; - s << "ServiceManager: unknown exception while starting service " << service; + if(info.communicator) + { + destroyServiceCommunicator(info.name, info.communicator); + } - FailureException e(__FILE__, __LINE__); - e.reason = s.str(); - throw e; + throw; } } @@ -764,7 +738,7 @@ IceBox::ServiceManagerI::stopAll() info.status = Stopped; stoppedServices.push_back(info.name); } - catch(const Ice::Exception& ex) + catch(const Exception& ex) { Warning out(_logger); out << "ServiceManager: exception while stopping service " << info.name << ":\n"; @@ -798,14 +772,14 @@ IceBox::ServiceManagerI::stopAll() info.communicator->shutdown(); info.communicator->waitForShutdown(); } - catch(const Ice::CommunicatorDestroyedException&) + catch(const CommunicatorDestroyedException&) { // // Ignore, the service might have already destroyed // the communicator for its own reasons. // } - catch(const Ice::Exception& ex) + catch(const Exception& ex) { Warning out(_logger); out << "ServiceManager: exception while stopping service " << info.name << ":\n"; @@ -983,3 +957,37 @@ ServiceManagerI::observerCompleted(const Ice::AsyncResultPtr& result) } } } + +void +IceBox::ServiceManagerI::destroyServiceCommunicator(const string& service, const CommunicatorPtr& communicator) +{ + try + { + communicator->shutdown(); + communicator->waitForShutdown(); + } + catch(const CommunicatorDestroyedException&) + { + // + // Ignore, the service might have already destroyed + // the communicator for its own reasons. + // + } + catch(const Exception& ex) + { + Warning out(_logger); + out << "ServiceManager: exception in shutting down communicator for service " << service << ":\n"; + out << ex; + } + + try + { + communicator->destroy(); + } + catch(const Exception& ex) + { + Warning out(_logger); + out << "ServiceManager: exception in shutting down communicator for service " << service << ":\n"; + out << ex; + } +} diff --git a/cpp/src/IceBox/ServiceManagerI.h b/cpp/src/IceBox/ServiceManagerI.h index 9c381941b49..a2b5388f4a8 100644 --- a/cpp/src/IceBox/ServiceManagerI.h +++ b/cpp/src/IceBox/ServiceManagerI.h @@ -70,6 +70,7 @@ private: void observerRemoved(const ServiceObserverPrx&, const std::exception&); Ice::PropertiesPtr createServiceProperties(const std::string&); + void destroyServiceCommunicator(const std::string&, const Ice::CommunicatorPtr&); ::Ice::CommunicatorPtr _communicator; ::Ice::CommunicatorPtr _sharedCommunicator; diff --git a/cpp/src/IceGrid/AdminI.cpp b/cpp/src/IceGrid/AdminI.cpp index 7453a93902b..624f143c1ba 100644 --- a/cpp/src/IceGrid/AdminI.cpp +++ b/cpp/src/IceGrid/AdminI.cpp @@ -187,7 +187,7 @@ void AdminI::syncApplication(const ApplicationDescriptor& descriptor, const Current&) { checkIsReadOnly(); - _database->syncApplicationDescriptor(descriptor, _session.get()); + _database->syncApplicationDescriptor(descriptor, false, _session.get()); } void @@ -200,7 +200,27 @@ AdminI::updateApplication(const ApplicationUpdateDescriptor& descriptor, const C update.updateUser = _session->getId(); update.descriptor = descriptor; update.revision = -1; // The database will set it. - _database->updateApplication(update, _session.get()); + _database->updateApplication(update, false, _session.get()); +} + +void +AdminI::syncApplicationWithoutRestart(const ApplicationDescriptor& descriptor, const Current&) +{ + checkIsReadOnly(); + _database->syncApplicationDescriptor(descriptor, true, _session.get()); +} + +void +AdminI::updateApplicationWithoutRestart(const ApplicationUpdateDescriptor& descriptor, const Current&) +{ + checkIsReadOnly(); + + ApplicationUpdateInfo update; + update.updateTime = IceUtil::Time::now().toMilliSeconds(); + update.updateUser = _session->getId(); + update.descriptor = descriptor; + update.revision = -1; // The database will set it. + _database->updateApplication(update, true, _session.get()); } void diff --git a/cpp/src/IceGrid/AdminI.h b/cpp/src/IceGrid/AdminI.h index 5ed1c5ee11c..864170dec19 100644 --- a/cpp/src/IceGrid/AdminI.h +++ b/cpp/src/IceGrid/AdminI.h @@ -36,6 +36,8 @@ public: virtual void addApplication(const ApplicationDescriptor&, const Ice::Current&); virtual void syncApplication(const ApplicationDescriptor&, const Ice::Current&); virtual void updateApplication(const ApplicationUpdateDescriptor&, const Ice::Current&); + virtual void syncApplicationWithoutRestart(const ApplicationDescriptor&, const Ice::Current&); + virtual void updateApplicationWithoutRestart(const ApplicationUpdateDescriptor&, const Ice::Current&); virtual void removeApplication(const std::string&, const Ice::Current&); virtual void instantiateServer(const std::string&, const std::string&, const ServerInstanceDescriptor&, const Ice::Current&); diff --git a/cpp/src/IceGrid/Database.cpp b/cpp/src/IceGrid/Database.cpp index 9326ea2e62f..0d8fb7888dd 100644 --- a/cpp/src/IceGrid/Database.cpp +++ b/cpp/src/IceGrid/Database.cpp @@ -43,30 +43,6 @@ struct ObjectLoadCI : binary_function<pair<Ice::ObjectPrx, float>&, pair<Ice::Ob } }; -bool -isServerUpdated(const ServerInfo& lhs, const ServerInfo& rhs) -{ - if(lhs.node != rhs.node) - { - return true; - } - - IceBoxDescriptorPtr lhsIceBox = IceBoxDescriptorPtr::dynamicCast(lhs.descriptor); - IceBoxDescriptorPtr rhsIceBox = IceBoxDescriptorPtr::dynamicCast(rhs.descriptor); - if(lhsIceBox && rhsIceBox) - { - return IceBoxHelper(lhsIceBox) != IceBoxHelper(rhsIceBox); - } - else if(!lhsIceBox && !rhsIceBox) - { - return ServerHelper(lhs.descriptor) != ServerHelper(rhs.descriptor); - } - else - { - return true; - } -} - void halt(const Ice::CommunicatorPtr& com, const DatabaseException& ex) { @@ -275,7 +251,7 @@ Database::syncApplications(const ApplicationInfoSeq& newApplications) { ApplicationHelper previous(_communicator, q->second.descriptor); ApplicationHelper helper(_communicator, p->descriptor); - reload(previous, helper, entries, p->uuid, p->revision); + reload(previous, helper, entries, p->uuid, p->revision, false); } else { @@ -466,12 +442,12 @@ Database::addApplication(const ApplicationInfo& info, AdminSessionI* session) } void -Database::updateApplication(const ApplicationUpdateInfo& updt, AdminSessionI* session) +Database::updateApplication(const ApplicationUpdateInfo& updt, bool noRestart, AdminSessionI* session) { - ServerEntrySeq entries; ApplicationInfo oldApp; - ApplicationDescriptor newDesc; ApplicationUpdateInfo update = updt; + auto_ptr<ApplicationHelper> previous; + auto_ptr<ApplicationHelper> helper; try { Lock sync(*this); @@ -495,20 +471,8 @@ Database::updateApplication(const ApplicationUpdateInfo& updt, AdminSessionI* se update.revision = oldApp.revision + 1; } - ApplicationHelper previous(_communicator, oldApp.descriptor); - ApplicationHelper helper(_communicator, previous.update(update.descriptor), true); - newDesc = helper.getDefinition(); - - checkForUpdate(previous, helper, connection); - - ApplicationInfo info = oldApp; - info.updateTime = update.updateTime; - info.updateUser = update.updateUser; - info.revision = update.revision; - info.descriptor = newDesc; - saveApplication(info, connection); - - reload(previous, helper, entries, oldApp.uuid, oldApp.revision + 1); + previous.reset(new ApplicationHelper(_communicator, oldApp.descriptor)); + helper.reset(new ApplicationHelper(_communicator, previous->update(update.descriptor), true)); startUpdating(update.descriptor.name, oldApp.uuid, oldApp.revision + 1); } @@ -517,15 +481,16 @@ Database::updateApplication(const ApplicationUpdateInfo& updt, AdminSessionI* se halt(_communicator, ex); } - finishApplicationUpdate(entries, update, oldApp, newDesc, session); + finishApplicationUpdate(update, oldApp, *previous, *helper, session, noRestart); } void -Database::syncApplicationDescriptor(const ApplicationDescriptor& newDesc, AdminSessionI* session) +Database::syncApplicationDescriptor(const ApplicationDescriptor& newDesc, bool noRestart, AdminSessionI* session) { - ServerEntrySeq entries; ApplicationUpdateInfo update; ApplicationInfo oldApp; + auto_ptr<ApplicationHelper> previous; + auto_ptr<ApplicationHelper> helper; try { Lock sync(*this); @@ -544,25 +509,14 @@ Database::syncApplicationDescriptor(const ApplicationDescriptor& newDesc, AdminS throw ApplicationNotExistException(newDesc.name); } - ApplicationHelper previous(_communicator, oldApp.descriptor); - ApplicationHelper helper(_communicator, newDesc, true); + previous.reset(new ApplicationHelper(_communicator, oldApp.descriptor)); + helper.reset(new ApplicationHelper(_communicator, newDesc, true)); update.updateTime = IceUtil::Time::now().toMilliSeconds(); update.updateUser = _lockUserId; update.revision = oldApp.revision + 1; - update.descriptor = helper.diff(previous); + update.descriptor = helper->diff(*previous); - checkForUpdate(previous, helper, connection); - - ApplicationInfo info = oldApp; - info.updateTime = update.updateTime; - info.updateUser = update.updateUser; - info.revision = update.revision; - info.descriptor = newDesc; - saveApplication(info, connection); - - reload(previous, helper, entries, oldApp.uuid, oldApp.revision + 1); - startUpdating(update.descriptor.name, oldApp.uuid, oldApp.revision + 1); } catch(const DatabaseException& ex) @@ -570,7 +524,7 @@ Database::syncApplicationDescriptor(const ApplicationDescriptor& newDesc, AdminS halt(_communicator, ex); } - finishApplicationUpdate(entries, update, oldApp, newDesc, session); + finishApplicationUpdate(update, oldApp, *previous, *helper, session, noRestart); } void @@ -579,10 +533,10 @@ Database::instantiateServer(const string& application, const ServerInstanceDescriptor& instance, AdminSessionI* session) { - ServerEntrySeq entries; ApplicationUpdateInfo update; ApplicationInfo oldApp; - ApplicationDescriptor newDesc; + auto_ptr<ApplicationHelper> previous; + auto_ptr<ApplicationHelper> helper; try { @@ -602,25 +556,13 @@ Database::instantiateServer(const string& application, throw ApplicationNotExistException(application); } - ApplicationHelper previous(_communicator, oldApp.descriptor); - ApplicationHelper helper(_communicator, previous.instantiateServer(node, instance), true); - newDesc = helper.getDefinition(); + previous.reset(new ApplicationHelper(_communicator, oldApp.descriptor)); + helper.reset(new ApplicationHelper(_communicator, previous->instantiateServer(node, instance), true)); update.updateTime = IceUtil::Time::now().toMilliSeconds(); update.updateUser = _lockUserId; update.revision = oldApp.revision + 1; - update.descriptor = helper.diff(previous); - - checkForUpdate(previous, helper, connection); - - ApplicationInfo info = oldApp; - info.updateTime = update.updateTime; - info.updateUser = update.updateUser; - info.revision = update.revision; - info.descriptor = newDesc; - saveApplication(info, connection); - - reload(previous, helper, entries, oldApp.uuid, oldApp.revision + 1); + update.descriptor = helper->diff(*previous); startUpdating(update.descriptor.name, oldApp.uuid, oldApp.revision + 1); } @@ -629,7 +571,7 @@ Database::instantiateServer(const string& application, halt(_communicator, ex); } - finishApplicationUpdate(entries, update, oldApp, newDesc, session); + finishApplicationUpdate(update, oldApp, *previous, *helper, session, true); } void @@ -1034,7 +976,7 @@ Database::getAdapterInfo(const string& id) // Otherwise, we check the adapter endpoint table -- if there's an // entry the adapter is managed by the registry itself. // - DatabaseConnectionPtr connection = _databaseCache->getConnection(); + DatabaseConnectionPtr connection = _databaseCache->newConnection(); AdaptersWrapperPtr adaptersWrapper = _databaseCache->getAdapters(connection); AdapterInfoSeq infos; try @@ -1878,7 +1820,7 @@ Database::load(const ApplicationHelper& app, ServerEntrySeq& entries, const stri map<string, ServerInfo> servers = app.getServerInfos(uuid, revision); for(map<string, ServerInfo>::const_iterator p = servers.begin(); p != servers.end(); ++p) { - entries.push_back(_serverCache.add(p->second)); + entries.push_back(_serverCache.add(p->second, false)); } } @@ -1914,7 +1856,8 @@ Database::reload(const ApplicationHelper& oldApp, const ApplicationHelper& newApp, ServerEntrySeq& entries, const string& uuid, - int revision) + int revision, + bool noRestart) { const string application = oldApp.getInstance().name; @@ -1940,7 +1883,7 @@ Database::reload(const ApplicationHelper& oldApp, else { ServerEntryPtr server = _serverCache.get(p->first); - server->update(q->second); // Just update the server revision on the node. + server->update(q->second, noRestart); // Just update the server revision on the node. entries.push_back(server); } } @@ -2028,7 +1971,7 @@ Database::reload(const ApplicationHelper& oldApp, // for(vector<ServerInfo>::const_iterator q = load.begin(); q != load.end(); ++q) { - entries.push_back(_serverCache.add(*q)); + entries.push_back(_serverCache.add(*q, noRestart)); } } @@ -2081,17 +2024,205 @@ Database::removeApplication(const string& name, const DatabaseConnectionPtr& con } void -Database::finishApplicationUpdate(ServerEntrySeq& entries, - const ApplicationUpdateInfo& update, - const ApplicationInfo& oldApp, - const ApplicationDescriptor& newDesc, - AdminSessionI* session) +Database::checkUpdate(const ApplicationHelper& oldApp, + const ApplicationHelper& newApp, + const string& uuid, + int revision, + bool noRestart) { + const string application = oldApp.getInstance().name; + + map<string, ServerInfo> oldServers = oldApp.getServerInfos(uuid, revision); + map<string, ServerInfo> newServers = newApp.getServerInfos(uuid, revision + 1); + + map<string, ServerInfo>::const_iterator p; + vector<string> servers; + vector<string> reasons; + if(noRestart) + { + for(p = oldServers.begin(); p != oldServers.end(); ++p) + { + map<string, ServerInfo>::const_iterator q = newServers.find(p->first); + if(q == newServers.end()) + { + servers.push_back(p->first); + reasons.push_back("server `" + p->first + "' needs to be removed"); + } + } + } + + vector<CheckUpdateResultPtr> results; + set<string> unreachableNodes; + for(p = newServers.begin(); p != newServers.end(); ++p) + { + map<string, ServerInfo>::const_iterator q = oldServers.find(p->first); + if(q != oldServers.end() && isServerUpdated(p->second, q->second)) + { + if(noRestart && isServerUpdated(p->second, q->second, true)) // Ignore properties + { + // + // The updates are not only property updates and noRestart is required, no + // need to check the server update on the node, we know already it requires + // a restart. + // + servers.push_back(p->first); + reasons.push_back("update requires the server `" + p->first + "' to be stopped"); + } + else + { + // + // Ask the node to check the server update. + // + try + { + CheckUpdateResultPtr result = _serverCache.get(p->first)->checkUpdate(p->second, noRestart); + if(result) + { + results.push_back(result); + } + } + catch(const NodeUnreachableException& ex) + { + unreachableNodes.insert(ex.name); + } + catch(const DeploymentException& ex) + { + servers.push_back(p->first); + reasons.push_back(ex.reason); + } + + } + } + } + + for(vector<CheckUpdateResultPtr>::const_iterator q = results.begin(); q != results.end(); ++q) + { + try + { + (*q)->getResult(); + } + catch(const NodeUnreachableException& ex) + { + unreachableNodes.insert(ex.name); + } + catch(const DeploymentException& ex) + { + servers.push_back((*q)->getServer()); + reasons.push_back(ex.reason); + } + } + + if(noRestart) + { + if(!servers.empty() || !unreachableNodes.empty()) + { + if(_traceLevels->application > 0) + { + Ice::Trace out(_traceLevels->logger, _traceLevels->applicationCat); + out << "check for application `" << application << "' update failed:"; + if(!unreachableNodes.empty()) + { + Ice::StringSeq nodes(unreachableNodes.begin(), unreachableNodes.end()); + if(nodes.size() == 1) + { + out << "\nthe node `" << nodes[0] << "' is down"; + } + else + { + out << "\nthe nodes `" << toString(nodes, ", ") << "' are down"; + } + } + if(!reasons.empty()) + { + for(vector<string>::const_iterator p = reasons.begin(); p != reasons.end(); ++p) + { + out << "\n" << *p; + } + } + } + + ostringstream os; + os << "check for application `" << application << "' update failed:"; + if(!servers.empty()) + { + if(servers.size() == 1) + { + os << "\nthe server `" << servers[0] << "' would need to be stopped"; + } + else + { + os << "\nthe servers `" << toString(servers, ", ") << "' would need to be stopped"; + } + } + if(!unreachableNodes.empty()) + { + Ice::StringSeq nodes(unreachableNodes.begin(), unreachableNodes.end()); + if(nodes.size() == 1) + { + os << "\nthe node `" << nodes[0] << "' is down"; + } + else + { + os << "\nthe nodes `" << toString(nodes, ", ") << "' are down"; + } + } + throw DeploymentException(os.str()); + } + } + else if(!reasons.empty()) + { + ostringstream os; + os << "check for application `" << application << "' update failed:"; + for(vector<string>::const_iterator p = reasons.begin(); p != reasons.end(); ++p) + { + os << "\n" << *p; + } + throw DeploymentException(os.str()); + } +} + +void +Database::finishApplicationUpdate(const ApplicationUpdateInfo& update, + const ApplicationInfo& oldApp, + const ApplicationHelper& previous, + const ApplicationHelper& helper, + AdminSessionI* session, + bool noRestart) +{ + const ApplicationDescriptor& newDesc = helper.getDefinition(); + DatabaseConnectionPtr connection = _databaseCache->newConnection(); + + ServerEntrySeq entries; + try + { + if(_master) + { + checkUpdate(previous, helper, oldApp.uuid, oldApp.revision, noRestart); + } + + Lock sync(*this); + checkForUpdate(previous, helper, connection); + reload(previous, helper, entries, oldApp.uuid, oldApp.revision + 1, noRestart); + } + catch(const DeploymentException&) + { + finishUpdating(update.descriptor.name); + throw; + } + for_each(entries.begin(), entries.end(), IceUtil::voidMemFun(&ServerEntry::sync)); int serial; { Lock sync(*this); + + ApplicationInfo info = oldApp; + info.updateTime = update.updateTime; + info.updateUser = update.updateUser; + info.revision = update.revision; + info.descriptor = newDesc; + saveApplication(info, connection); + ++_applicationSerial; serial = _applicationObserverTopic->applicationUpdated(_applicationSerial, update); } @@ -2135,8 +2266,8 @@ Database::finishApplicationUpdate(ServerEntrySeq& entries, ApplicationInfo info = oldApp; info.revision = update.revision + 1; - saveApplication(info, _databaseCache->getConnection()); - reload(previous, helper, entries, info.uuid, info.revision); + saveApplication(info, connection); + reload(previous, helper, entries, info.uuid, info.revision, noRestart); newUpdate.updateTime = IceUtil::Time::now().toMilliSeconds(); newUpdate.updateUser = _lockUserId; diff --git a/cpp/src/IceGrid/Database.h b/cpp/src/IceGrid/Database.h index bd437619dcf..e3bae73ab67 100644 --- a/cpp/src/IceGrid/Database.h +++ b/cpp/src/IceGrid/Database.h @@ -73,8 +73,8 @@ public: void syncObjects(const ObjectInfoSeq&); void addApplication(const ApplicationInfo&, AdminSessionI* = 0); - void updateApplication(const ApplicationUpdateInfo&, AdminSessionI* = 0); - void syncApplicationDescriptor(const ApplicationDescriptor&, AdminSessionI* = 0); + void updateApplication(const ApplicationUpdateInfo&, bool, AdminSessionI* = 0); + void syncApplicationDescriptor(const ApplicationDescriptor&, bool, AdminSessionI* = 0); void instantiateServer(const std::string&, const std::string&, const ServerInstanceDescriptor&, AdminSessionI* =0); void removeApplication(const std::string&, AdminSessionI* = 0); ApplicationInfo getApplicationInfo(const std::string&); @@ -140,13 +140,15 @@ private: void load(const ApplicationHelper&, ServerEntrySeq&, const std::string&, int); void unload(const ApplicationHelper&, ServerEntrySeq&); - void reload(const ApplicationHelper&, const ApplicationHelper&, ServerEntrySeq&, const std::string&, int); + void reload(const ApplicationHelper&, const ApplicationHelper&, ServerEntrySeq&, const std::string&, int, bool); + + void checkUpdate(const ApplicationHelper&, const ApplicationHelper&, const std::string&, int, bool); void saveApplication(const ApplicationInfo&, const IceDB::DatabaseConnectionPtr&); void removeApplication(const std::string&, const IceDB::DatabaseConnectionPtr&); - void finishApplicationUpdate(ServerEntrySeq&, const ApplicationUpdateInfo&, const ApplicationInfo&, - const ApplicationDescriptor&, AdminSessionI*); + void finishApplicationUpdate(const ApplicationUpdateInfo&, const ApplicationInfo&, const ApplicationHelper&, + const ApplicationHelper&, AdminSessionI*, bool); void checkSessionLock(AdminSessionI*); diff --git a/cpp/src/IceGrid/DescriptorHelper.cpp b/cpp/src/IceGrid/DescriptorHelper.cpp index 67467f280f9..ce9a74810e6 100644 --- a/cpp/src/IceGrid/DescriptorHelper.cpp +++ b/cpp/src/IceGrid/DescriptorHelper.cpp @@ -915,8 +915,8 @@ Resolver::checkReserved(const string& type, const map<string, string>& values) c } } -CommunicatorHelper::CommunicatorHelper(const CommunicatorDescriptorPtr& desc) : - _desc(desc) +CommunicatorHelper::CommunicatorHelper(const CommunicatorDescriptorPtr& desc, bool ignoreProps) : + _desc(desc), _ignoreProps(ignoreProps) { } @@ -939,9 +939,12 @@ CommunicatorHelper::operator==(const CommunicatorHelper& helper) const return false; } - if(_desc->propertySet != helper._desc->propertySet) + if(!_ignoreProps) { - return false; + if(_desc->propertySet != helper._desc->propertySet) + { + return false; + } } if(set<DbEnvDescriptor>(_desc->dbEnvs.begin(), _desc->dbEnvs.end()) != @@ -1206,8 +1209,8 @@ CommunicatorHelper::getProperty(const string& name) const return IceGrid::getProperty(_desc->propertySet.properties, name); } -ServiceHelper::ServiceHelper(const ServiceDescriptorPtr& descriptor) : - CommunicatorHelper(descriptor), +ServiceHelper::ServiceHelper(const ServiceDescriptorPtr& descriptor, bool ignoreProps) : + CommunicatorHelper(descriptor, ignoreProps), _desc(descriptor) { } @@ -1284,8 +1287,8 @@ ServiceHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) cons out << eb; } -ServerHelper::ServerHelper(const ServerDescriptorPtr& descriptor) : - CommunicatorHelper(descriptor), +ServerHelper::ServerHelper(const ServerDescriptorPtr& descriptor, bool ignoreProps) : + CommunicatorHelper(descriptor, ignoreProps), _desc(descriptor) { } @@ -1504,13 +1507,13 @@ ServerHelper::instantiateImpl(const ServerDescriptorPtr& instance, instance->propertySet.properties.insert(instance->propertySet.properties.end(), props.begin(), props.end()); } -IceBoxHelper::IceBoxHelper(const IceBoxDescriptorPtr& descriptor) : - ServerHelper(descriptor), +IceBoxHelper::IceBoxHelper(const IceBoxDescriptorPtr& descriptor, bool ignoreProps) : + ServerHelper(descriptor, ignoreProps), _desc(descriptor) { for(ServiceInstanceDescriptorSeq::const_iterator p = _desc->services.begin(); p != _desc->services.end(); ++p) { - _services.push_back(ServiceInstanceHelper(*p)); + _services.push_back(ServiceInstanceHelper(*p, ignoreProps)); } } @@ -1671,7 +1674,7 @@ InstanceHelper::instantiateParams(const Resolver& resolve, return params; } -ServiceInstanceHelper::ServiceInstanceHelper(const ServiceInstanceDescriptor& desc) : +ServiceInstanceHelper::ServiceInstanceHelper(const ServiceInstanceDescriptor& desc, bool ignoreProps) : _def(desc) { // @@ -1686,7 +1689,7 @@ ServiceInstanceHelper::ServiceInstanceHelper(const ServiceInstanceDescriptor& de if(_def.descriptor) { - _service = ServiceHelper(_def.descriptor); + _service = ServiceHelper(_def.descriptor, ignoreProps); } } @@ -3153,17 +3156,17 @@ ApplicationHelper::printDiff(Output& out, const ApplicationHelper& helper) const } bool -IceGrid::descriptorEqual(const ServerDescriptorPtr& lhs, const ServerDescriptorPtr& rhs) +IceGrid::descriptorEqual(const ServerDescriptorPtr& lhs, const ServerDescriptorPtr& rhs, bool ignoreProps) { IceBoxDescriptorPtr lhsIceBox = IceBoxDescriptorPtr::dynamicCast(lhs); IceBoxDescriptorPtr rhsIceBox = IceBoxDescriptorPtr::dynamicCast(rhs); if(lhsIceBox && rhsIceBox) { - return IceBoxHelper(lhsIceBox) == IceBoxHelper(rhsIceBox); + return IceBoxHelper(lhsIceBox, ignoreProps) == IceBoxHelper(rhsIceBox, ignoreProps); } else if(!lhsIceBox && !rhsIceBox) { - return ServerHelper(lhs) == ServerHelper(rhs); + return ServerHelper(lhs, ignoreProps) == ServerHelper(rhs, ignoreProps); } else { @@ -3184,3 +3187,13 @@ IceGrid::createHelper(const ServerDescriptorPtr& desc) return new ServerHelper(desc); } } + +bool +IceGrid::isServerUpdated(const ServerInfo& lhs, const ServerInfo& rhs, bool ignoreProps) +{ + if(lhs.node != rhs.node) + { + return true; + } + return !descriptorEqual(lhs.descriptor, rhs.descriptor, ignoreProps); +} diff --git a/cpp/src/IceGrid/DescriptorHelper.h b/cpp/src/IceGrid/DescriptorHelper.h index b2b012c5e49..eeda3eee3a1 100644 --- a/cpp/src/IceGrid/DescriptorHelper.h +++ b/cpp/src/IceGrid/DescriptorHelper.h @@ -85,8 +85,8 @@ class CommunicatorHelper { public: - CommunicatorHelper(const CommunicatorDescriptorPtr&); - CommunicatorHelper() { } + CommunicatorHelper(const CommunicatorDescriptorPtr&, bool = false); + CommunicatorHelper() : _ignoreProps(false) { } virtual ~CommunicatorHelper() { } virtual bool operator==(const CommunicatorHelper&) const; @@ -109,13 +109,14 @@ protected: private: CommunicatorDescriptorPtr _desc; + bool _ignoreProps; }; class ServiceHelper : public CommunicatorHelper { public: - ServiceHelper(const ServiceDescriptorPtr&); + ServiceHelper(const ServiceDescriptorPtr&, bool = false); ServiceHelper() { } virtual bool operator==(const CommunicatorHelper&) const; @@ -143,7 +144,7 @@ class ServerHelper : public CommunicatorHelper, public IceUtil::SimpleShared { public: - ServerHelper(const ServerDescriptorPtr&); + ServerHelper(const ServerDescriptorPtr&, bool = false); ServerHelper() { } virtual bool operator==(const CommunicatorHelper&) const; @@ -185,7 +186,7 @@ class ServiceInstanceHelper : public InstanceHelper { public: - ServiceInstanceHelper(const ServiceInstanceDescriptor&); + ServiceInstanceHelper(const ServiceInstanceDescriptor&, bool); bool operator==(const ServiceInstanceHelper&) const; bool operator!=(const ServiceInstanceHelper&) const; @@ -207,7 +208,7 @@ class IceBoxHelper : public ServerHelper { public: - IceBoxHelper(const IceBoxDescriptorPtr&); + IceBoxHelper(const IceBoxDescriptorPtr&, bool = false); IceBoxHelper() { } virtual bool operator==(const CommunicatorHelper&) const; @@ -339,7 +340,8 @@ private: NodeHelperDict _nodes; }; -bool descriptorEqual(const ServerDescriptorPtr&, const ServerDescriptorPtr&); +bool descriptorEqual(const ServerDescriptorPtr&, const ServerDescriptorPtr&, bool = false); ServerHelperPtr createHelper(const ServerDescriptorPtr&); +bool isServerUpdated(const ServerInfo&, const ServerInfo&, bool = false); } diff --git a/cpp/src/IceGrid/Internal.ice b/cpp/src/IceGrid/Internal.ice index 1362ff7bbe7..bb5ae9b9907 100644 --- a/cpp/src/IceGrid/Internal.ice +++ b/cpp/src/IceGrid/Internal.ice @@ -239,6 +239,18 @@ interface Server extends FileReader /** * + * Check if the given server can be loaded on this node. + * + * @return True if the server is inactive. + * + * @throws DeploymentException Raised if the server can't be updated. + * + **/ + ["ami"] bool checkUpdate(InternalServerDescriptor svr, bool noRestart) + throws DeploymentException; + + /** + * * Enable or disable the server. * **/ @@ -359,6 +371,22 @@ interface Node extends FileReader, ReplicaObserver /** * + * Load the given server and ensure the server won't be + * restarted. If the server resources weren't already created + * (database environment directories, property files, etc), they + * will be created. If the server can't be updated without a + * restart, a DeploymentException is raised. + * + **/ + ["amd"] idempotent Server* loadServerWithoutRestart(InternalServerDescriptor svr, + string replicaName, + out AdapterPrxDict adapters, + out int actTimeout, + out int deactTimeout) + throws DeploymentException; + + /** + * * Destroy the given server. * **/ diff --git a/cpp/src/IceGrid/NodeCache.cpp b/cpp/src/IceGrid/NodeCache.cpp index e03a74e51d9..c2d69d64e05 100644 --- a/cpp/src/IceGrid/NodeCache.cpp +++ b/cpp/src/IceGrid/NodeCache.cpp @@ -182,10 +182,7 @@ class LoadCB : virtual public IceUtil::Shared { public: - LoadCB(const TraceLevelsPtr& traceLevels, - const ServerEntryPtr& server, - const string& node, - int timeout) : + LoadCB(const TraceLevelsPtr& traceLevels, const ServerEntryPtr& server, const string& node, int timeout) : _traceLevels(traceLevels), _server(server), _id(server->getId()), _node(node), _timeout(timeout) { } @@ -549,7 +546,8 @@ NodeEntry::canRemove() } void -NodeEntry::loadServer(const ServerEntryPtr& entry, const ServerInfo& server, const SessionIPtr& session, int timeout) +NodeEntry::loadServer(const ServerEntryPtr& entry, const ServerInfo& server, const SessionIPtr& session, int timeout, + bool noRestart) { try { @@ -600,12 +598,23 @@ NodeEntry::loadServer(const ServerEntryPtr& entry, const ServerInfo& server, con out << " for session `" << session->getId() << "'"; } } - - node->begin_loadServer(desc, _cache.getReplicaName(), - newCallback_Node_loadServer( - new LoadCB(_cache.getTraceLevels(), entry, _name, sessionTimeout), - &LoadCB::response, - &LoadCB::exception)); + + if(noRestart) + { + node->begin_loadServerWithoutRestart(desc, _cache.getReplicaName(), + newCallback_Node_loadServerWithoutRestart( + new LoadCB(_cache.getTraceLevels(), entry, _name, sessionTimeout), + &LoadCB::response, + &LoadCB::exception)); + } + else + { + node->begin_loadServer(desc, _cache.getReplicaName(), + newCallback_Node_loadServer( + new LoadCB(_cache.getTraceLevels(), entry, _name, sessionTimeout), + &LoadCB::response, + &LoadCB::exception)); + } } catch(const NodeUnreachableException& ex) { @@ -665,31 +674,27 @@ NodeEntry::getServerInfo(const ServerInfo& server, const SessionIPtr& session) return info; } -ServerDescriptorPtr -NodeEntry::getServerDescriptor(const ServerInfo& server, const SessionIPtr& session) +InternalServerDescriptorPtr +NodeEntry::getInternalServerDescriptor(const ServerInfo& server, const SessionIPtr& session) { - assert(_session); - - Resolver resolve(_session->getInfo(), _cache.getCommunicator()); - resolve.setReserved("application", server.application); - resolve.setReserved("server", server.descriptor->id); - resolve.setContext("server `${server}'"); - - if(session) - { - resolve.setReserved("session.id", session->getId()); - } - - IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(server.descriptor); - if(iceBox) + Lock sync(*this); + checkSession(); + + ServerInfo info = server; + try { - return IceBoxHelper(iceBox).instantiate(resolve, PropertyDescriptorSeq(), PropertySetDescriptorDict()); + info.descriptor = getServerDescriptor(server, session); } - else + catch(const DeploymentException&) { - return ServerHelper(server.descriptor).instantiate(resolve, PropertyDescriptorSeq(), - PropertySetDescriptorDict()); + // + // We ignore the deployment error for now (which can + // only be caused in theory by session variables not + // being defined because the server isn't + // allocated...) + // } + return getInternalServerDescriptor(info); } void @@ -854,6 +859,33 @@ NodeEntry::finishedRegistration(const Ice::Exception& ex) } } +ServerDescriptorPtr +NodeEntry::getServerDescriptor(const ServerInfo& server, const SessionIPtr& session) +{ + assert(_session); + + Resolver resolve(_session->getInfo(), _cache.getCommunicator()); + resolve.setReserved("application", server.application); + resolve.setReserved("server", server.descriptor->id); + resolve.setContext("server `${server}'"); + + if(session) + { + resolve.setReserved("session.id", session->getId()); + } + + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(server.descriptor); + if(iceBox) + { + return IceBoxHelper(iceBox).instantiate(resolve, PropertyDescriptorSeq(), PropertySetDescriptorDict()); + } + else + { + return ServerHelper(server.descriptor).instantiate(resolve, PropertyDescriptorSeq(), + PropertySetDescriptorDict()); + } +} + InternalServerDescriptorPtr NodeEntry::getInternalServerDescriptor(const ServerInfo& info) const { diff --git a/cpp/src/IceGrid/NodeCache.h b/cpp/src/IceGrid/NodeCache.h index 03b3a1a914d..af87fe2730b 100644 --- a/cpp/src/IceGrid/NodeCache.h +++ b/cpp/src/IceGrid/NodeCache.h @@ -53,9 +53,11 @@ public: bool canRemove(); - void loadServer(const ServerEntryPtr&, const ServerInfo&, const SessionIPtr&, int); + void loadServer(const ServerEntryPtr&, const ServerInfo&, const SessionIPtr&, int, bool); void destroyServer(const ServerEntryPtr&, const ServerInfo&, int); + ServerInfo getServerInfo(const ServerInfo&, const SessionIPtr&); + InternalServerDescriptorPtr getInternalServerDescriptor(const ServerInfo&, const SessionIPtr&); void __incRef(); void __decRef(); diff --git a/cpp/src/IceGrid/NodeI.cpp b/cpp/src/IceGrid/NodeI.cpp index 1c03de9c4fa..de95ba412d2 100644 --- a/cpp/src/IceGrid/NodeI.cpp +++ b/cpp/src/IceGrid/NodeI.cpp @@ -374,6 +374,7 @@ void NodeI::loadServer_async(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescriptorPtr& descriptor, const string& replicaName, + bool noRestart, const Ice::Current& current) { ServerCommandPtr command; @@ -418,7 +419,7 @@ NodeI::loadServer_async(const AMD_Node_loadServerPtr& amdCB, try { - command = server->load(amdCB, descriptor, replicaName); + command = server->load(amdCB, descriptor, replicaName, noRestart); } catch(const Ice::ObjectNotExistException&) { @@ -450,9 +451,57 @@ NodeI::loadServer_async(const AMD_Node_loadServerPtr& amdCB, } void -NodeI::destroyServer_async(const AMD_Node_destroyServerPtr& amdCB, - const string& serverId, - const string& uuid, +NodeI::loadServer_async(const AMD_Node_loadServerPtr& amdCB, + const InternalServerDescriptorPtr& descriptor, + const string& replicaName, + const Ice::Current& current) +{ + loadServer_async(amdCB, descriptor, replicaName, false, current); +} + +void +NodeI::loadServerWithoutRestart_async(const AMD_Node_loadServerWithoutRestartPtr& amdCB, + const InternalServerDescriptorPtr& descriptor, + const string& replicaName, + const Ice::Current& current) +{ + class LoadServerCB : public AMD_Node_loadServer + { + public: + + LoadServerCB(const AMD_Node_loadServerWithoutRestartPtr& cb) : _cb(cb) + { + } + + virtual void + ice_response(const ServerPrx& server, const AdapterPrxDict& adapters, Ice::Int actTimeout, Ice::Int deacTimeout) + { + _cb->ice_response(server, adapters, actTimeout, deacTimeout); + }; + + virtual void + ice_exception(const ::std::exception& ex) + { + _cb->ice_exception(ex); + } + + virtual void + ice_exception() + { + _cb->ice_exception(); + } + + private: + + const AMD_Node_loadServerWithoutRestartPtr _cb; + }; + loadServer_async(new LoadServerCB(amdCB), descriptor, replicaName, true, current); +} + +void +NodeI::destroyServer_async(const AMD_Node_destroyServerPtr& amdCB, + const string& serverId, + const string& uuid, int revision, const string& replicaName, const Ice::Current& current) diff --git a/cpp/src/IceGrid/NodeI.h b/cpp/src/IceGrid/NodeI.h index 508de0f2a48..39d39a976b8 100644 --- a/cpp/src/IceGrid/NodeI.h +++ b/cpp/src/IceGrid/NodeI.h @@ -68,8 +68,19 @@ public: virtual void loadServer_async(const AMD_Node_loadServerPtr&, const InternalServerDescriptorPtr&, const std::string&, + bool, const Ice::Current&); + virtual void loadServer_async(const AMD_Node_loadServerPtr&, + const InternalServerDescriptorPtr&, + const std::string&, + const Ice::Current&); + + virtual void loadServerWithoutRestart_async(const AMD_Node_loadServerWithoutRestartPtr&, + const InternalServerDescriptorPtr&, + const std::string&, + const Ice::Current&); + virtual void destroyServer_async(const AMD_Node_destroyServerPtr&, const std::string&, const std::string&, diff --git a/cpp/src/IceGrid/Parser.cpp b/cpp/src/IceGrid/Parser.cpp index e80d54408b1..4c068664e0a 100644 --- a/cpp/src/IceGrid/Parser.cpp +++ b/cpp/src/IceGrid/Parser.cpp @@ -51,13 +51,17 @@ const char* _commandsHelp[][3] = { "application describe NAME Describe application NAME.\n" }, { "application", "diff", -"application diff DESC [TARGET ... ] [NAME=VALUE ... ]\n" +"application diff [-s | --servers] DESC [TARGET ... ] [NAME=VALUE ... ]\n" " Print the differences betwen the application\n" " described in DESC and the current deployment.\n" +" If -s or --servers is specified, print the\n" +" the list of servers affected by the differences.\n" }, { "application", "update", -"application update DESC [TARGET ... ] [NAME=VALUE ... ]\n" -" Update the application described in DESC.\n" +"application update [-n | --no-restart] DESC [TARGET ... ] [NAME=VALUE ... ]\n" +" Update the application described in DESC. If -n or\n" +" --no-restart is specified, the update will fail if\n" +" it requires to stop some servers.\n" }, { "application", "patch", "application patch [-f | --force] NAME\n" @@ -475,8 +479,28 @@ Parser::describeApplication(const list<string>& args) } void -Parser::diffApplication(const list<string>& args) +Parser::diffApplication(const list<string>& origArgs) { + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("s", "servers"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + if(args.size() < 1) { invalidCommand("application diff" , "requires at least one argument"); @@ -488,7 +512,7 @@ Parser::diffApplication(const list<string>& args) StringSeq targets; map<string, string> vars; - list<string>::const_iterator p = args.begin(); + vector<string>::const_iterator p = args.begin(); string desc = *p++; for(; p != args.end(); ++p) @@ -511,7 +535,55 @@ Parser::diffApplication(const list<string>& args) ApplicationHelper oldAppHelper(_communicator, origApp.descriptor); Output out(cout); - newAppHelper.printDiff(out, oldAppHelper); + if(opts.isSet("servers")) + { + map<string, ServerInfo> oldServers = oldAppHelper.getServerInfos(origApp.uuid, origApp.revision); + map<string, ServerInfo> newServers = newAppHelper.getServerInfos(origApp.uuid, origApp.revision); + + vector<string> messages; + map<string, ServerInfo>::const_iterator p; + for(p = oldServers.begin(); p != oldServers.end(); ++p) + { + map<string, ServerInfo>::const_iterator q = newServers.find(p->first); + if(q == newServers.end()) + { + messages.push_back("server `" + p->first + "': removed"); + } + } + + for(p = newServers.begin(); p != newServers.end(); ++p) + { + map<string, ServerInfo>::const_iterator q = oldServers.find(p->first); + if(q == oldServers.end()) + { + messages.push_back("server `" + p->first + "': added"); + } + else if(isServerUpdated(p->second, q->second)) + { + if(isServerUpdated(p->second, q->second, true)) // Ignore properties + { + messages.push_back("server `" + p->first + "': updated (restart required)"); + } + else + { + messages.push_back("server `" + p->first + "': properties updated (no restart required)"); + } + } + } + + out << "application `" << origApp.descriptor.name << "'"; + out << sb; + sort(messages.begin(), messages.end()); + for(vector<string>::const_iterator r = messages.begin(); r != messages.end(); ++r) + { + out << nl << *r; + } + out << eb; + } + else + { + newAppHelper.printDiff(out, oldAppHelper); + } out << nl; } catch(const Ice::Exception& ex) @@ -521,8 +593,28 @@ Parser::diffApplication(const list<string>& args) } void -Parser::updateApplication(const list<string>& args) +Parser::updateApplication(const list<string>& origArgs) { + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("n", "no-restart"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + if(args.size() < 1) { invalidCommand("application update", "requires at least one argument"); @@ -534,8 +626,8 @@ Parser::updateApplication(const list<string>& args) StringSeq targets; map<string, string> vars; - list<string>::const_iterator p = args.begin(); - string desc = *p++; + vector<string>::const_iterator p = args.begin(); + string xml = *p++; for(; p != args.end(); ++p) { @@ -550,7 +642,19 @@ Parser::updateApplication(const list<string>& args) } } - _admin->syncApplication(DescriptorParser::parseDescriptor(desc, targets, vars, _communicator, _admin)); + ApplicationDescriptor desc = DescriptorParser::parseDescriptor(xml, targets, vars, _communicator, _admin); + if(opts.isSet("no-restart")) + { + _admin->syncApplicationWithoutRestart(desc); + } + else + { + _admin->syncApplication(desc); + } + } + catch(const Ice::OperationNotExistException&) + { + error("registry doesn't support updates without restart"); } catch(const Ice::Exception& ex) { diff --git a/cpp/src/IceGrid/ReplicaSessionManager.cpp b/cpp/src/IceGrid/ReplicaSessionManager.cpp index 8d478fddc8c..404571b7217 100644 --- a/cpp/src/IceGrid/ReplicaSessionManager.cpp +++ b/cpp/src/IceGrid/ReplicaSessionManager.cpp @@ -79,7 +79,7 @@ public: string failure; try { - _database->updateApplication(update); + _database->updateApplication(update, false); } catch(const DeploymentException& ex) { diff --git a/cpp/src/IceGrid/ServerCache.cpp b/cpp/src/IceGrid/ServerCache.cpp index d9be593a4af..5d8d8942b29 100644 --- a/cpp/src/IceGrid/ServerCache.cpp +++ b/cpp/src/IceGrid/ServerCache.cpp @@ -59,6 +59,45 @@ namespace IceGrid ServerCache& _serverCache; const ServerEntryPtr _entry; }; + + +} + +CheckUpdateResult::CheckUpdateResult(const string& server, + const string& node, + bool noRestart, + const Ice::AsyncResultPtr& result) : + _server(server), _node(node), _noRestart(noRestart), _result(result) +{ +} + +bool +CheckUpdateResult::getResult() +{ + try + { + return ServerPrx::uncheckedCast(_result->getProxy())->end_checkUpdate(_result); + } + catch(const DeploymentException& ex) + { + ostringstream os; + os << "check for server `" << _server << "' update failed: " << ex.reason; + throw DeploymentException(os.str()); + } + catch(const Ice::OperationNotExistException&) + { + if(_noRestart) + { + throw DeploymentException("server `" + _server + "' doesn't support check for updates"); + } + return false; + } + catch(const Ice::Exception& ex) + { + ostringstream os; + os << ex; + throw NodeUnreachableException(_node, os.str()); + } } ServerCache::ServerCache(const Ice::CommunicatorPtr& communicator, @@ -77,7 +116,7 @@ ServerCache::ServerCache(const Ice::CommunicatorPtr& communicator, } ServerEntryPtr -ServerCache::add(const ServerInfo& info) +ServerCache::add(const ServerInfo& info, bool noRestart) { Lock sync(*this); @@ -87,7 +126,7 @@ ServerCache::add(const ServerInfo& info) entry = new ServerEntry(*this, info.descriptor->id); addImpl(info.descriptor->id, entry); } - entry->update(info); + entry->update(info, noRestart); _nodeCache.get(info.node, true)->addServer(entry); forEachCommunicator(AddCommunicator(*this, entry, info.application))(info.descriptor); @@ -211,7 +250,8 @@ ServerEntry::ServerEntry(ServerCache& cache, const string& id) : _activationTimeout(-1), _deactivationTimeout(-1), _synchronizing(false), - _updated(false) + _updated(false), + _noRestart(false) { } @@ -273,7 +313,7 @@ ServerEntry::addSyncCallback(const SynchronizationCallbackPtr& callback) } void -ServerEntry::update(const ServerInfo& info) +ServerEntry::update(const ServerInfo& info, bool noRestart) { Lock sync(*this); @@ -295,6 +335,7 @@ ServerEntry::update(const ServerInfo& info) } _load = descriptor; + _noRestart = noRestart; _loaded.reset(0); _allocatable = info.descriptor->allocatable; if(info.descriptor->activation == "session") @@ -528,6 +569,7 @@ ServerEntry::syncImpl() SessionIPtr session; ServerInfo destroy; int timeout = -1; + bool noRestart; { Lock sync(*this); @@ -554,6 +596,7 @@ ServerEntry::syncImpl() load = *_load; session = _session; timeout = _deactivationTimeout; // loadServer might block to deactivate the previous server. + noRestart = _noRestart; } else { @@ -578,7 +621,7 @@ ServerEntry::syncImpl() { try { - _cache.getNodeCache().get(load.node)->loadServer(this, load, session, timeout); + _cache.getNodeCache().get(load.node)->loadServer(this, load, session, timeout, noRestart); } catch(NodeNotExistException&) { @@ -692,6 +735,7 @@ ServerEntry::loadCallback(const ServerPrx& proxy, const AdapterPrxDict& adpts, i ServerInfo destroy; int timeout = -1; bool synced = false; + bool noRestart; { Lock sync(*this); @@ -726,6 +770,7 @@ ServerEntry::loadCallback(const ServerPrx& proxy, const AdapterPrxDict& adpts, i else if(_load.get()) { load = *_load; + noRestart = _noRestart; session = _session; timeout = _deactivationTimeout; // loadServer might block to deactivate the previous server. } @@ -754,7 +799,7 @@ ServerEntry::loadCallback(const ServerPrx& proxy, const AdapterPrxDict& adpts, i { try { - _cache.getNodeCache().get(load.node)->loadServer(this, load, session, timeout); + _cache.getNodeCache().get(load.node)->loadServer(this, load, session, timeout, noRestart); } catch(NodeNotExistException&) { @@ -767,6 +812,7 @@ void ServerEntry::destroyCallback() { ServerInfo load; + bool noRestart; SessionIPtr session; { @@ -787,6 +833,7 @@ ServerEntry::destroyCallback() { _updated = false; load = *_load; + noRestart = _noRestart; session = _session; } } @@ -795,7 +842,7 @@ ServerEntry::destroyCallback() { try { - _cache.getNodeCache().get(load.node)->loadServer(this, load, session, -1); + _cache.getNodeCache().get(load.node)->loadServer(this, load, session, -1, noRestart); } catch(NodeNotExistException&) { @@ -814,6 +861,7 @@ ServerEntry::exception(const Ice::Exception& ex) { ServerInfo load; SessionIPtr session; + bool noRestart; bool remove = false; int timeout = -1; @@ -836,6 +884,7 @@ ServerEntry::exception(const Ice::Exception& ex) _destroy.reset(0); _updated = false; load = *_load.get(); + noRestart = _noRestart; session = _session; timeout = _deactivationTimeout; // loadServer might block to deactivate the previous server. } @@ -845,7 +894,7 @@ ServerEntry::exception(const Ice::Exception& ex) { try { - _cache.getNodeCache().get(load.node)->loadServer(this, load, session, timeout); + _cache.getNodeCache().get(load.node)->loadServer(this, load, session, timeout, noRestart); } catch(NodeNotExistException&) { @@ -876,6 +925,60 @@ ServerEntry::canRemove() return !_loaded.get() && !_load.get() && !_destroy.get(); } +CheckUpdateResultPtr +ServerEntry::checkUpdate(const ServerInfo& info, bool noRestart) +{ + SessionIPtr session; + { + Lock sync(*this); + if(!_loaded.get() && !_load.get()) + { + throw ServerNotExistException(); + } + + ServerInfo oldInfo = _loaded.get() ? *_loaded : *_load; + if(noRestart && info.node != oldInfo.node) + { + throw DeploymentException("server `" + _id + "' is moved to another node"); + } + + session = _session; + } + + NodeEntryPtr node; + try + { + node = _cache.getNodeCache().get(info.node); + } + catch(NodeNotExistException&) + { + throw NodeUnreachableException(info.node, "node is not active"); + } + + ServerPrx server; + try + { + server = getProxy(true); + } + catch(const DeploymentException&) + { + if(noRestart) + { + // If the server can't be loaded and no restart is required, we throw + // to indicate that the server update can't be checked. + throw; + } + else + { + // Otherwise, we do as if the update is valid. + return 0; + } + } + + InternalServerDescriptorPtr desc = node->getInternalServerDescriptor(info, session); + return new CheckUpdateResult(_id, info.node, noRestart, server->begin_checkUpdate(desc, noRestart)); + +} void ServerEntry::allocated(const SessionIPtr& session) diff --git a/cpp/src/IceGrid/ServerCache.h b/cpp/src/IceGrid/ServerCache.h index f1db17fa9b6..866ba3652aa 100644 --- a/cpp/src/IceGrid/ServerCache.h +++ b/cpp/src/IceGrid/ServerCache.h @@ -29,6 +29,28 @@ class NodeCache; class NodeEntry; typedef IceUtil::Handle<NodeEntry> NodeEntryPtr; +class CheckServerResult; +typedef IceUtil::Handle<CheckServerResult> CheckServerResultPtr; + +class CheckUpdateResult : public IceUtil::Shared +{ +public: + + CheckUpdateResult(const std::string&, const std::string&, bool, const Ice::AsyncResultPtr&); + + bool getResult(); + + const std::string& getServer() { return _server; } + +private: + + const std::string _server; + const std::string _node; + const bool _noRestart; + const Ice::AsyncResultPtr _result; +}; +typedef IceUtil::Handle<CheckUpdateResult> CheckUpdateResultPtr; + class ServerEntry : public Allocatable { public: @@ -50,7 +72,8 @@ public: bool addSyncCallback(const SynchronizationCallbackPtr&); - void update(const ServerInfo&); + void update(const ServerInfo&, bool); + void destroy(); ServerInfo getInfo(bool = false) const; @@ -65,6 +88,7 @@ public: float getLoad(LoadSample) const; bool canRemove(); + CheckUpdateResultPtr checkUpdate(const ServerInfo&, bool); bool isDestroyed(); void loadCallback(const ServerPrx&, const AdapterPrxDict&, int, int); @@ -96,6 +120,7 @@ private: bool _synchronizing; bool _updated; + bool _noRestart; std::auto_ptr<Ice::Exception> _exception; std::vector<SynchronizationCallbackPtr> _callbacks; @@ -114,7 +139,7 @@ public: ServerCache(const Ice::CommunicatorPtr&, const std::string&, NodeCache&, AdapterCache&, ObjectCache&, AllocatableObjectCache&); - ServerEntryPtr add(const ServerInfo&); + ServerEntryPtr add(const ServerInfo&, bool); ServerEntryPtr get(const std::string&) const; bool has(const std::string&) const; ServerEntryPtr remove(const std::string&, bool = true); diff --git a/cpp/src/IceGrid/ServerI.cpp b/cpp/src/IceGrid/ServerI.cpp index 4db7ef92f78..ae530bc5cdb 100755 --- a/cpp/src/IceGrid/ServerI.cpp +++ b/cpp/src/IceGrid/ServerI.cpp @@ -121,12 +121,16 @@ chownRecursive(const string& path, uid_t uid, gid_t gid) #endif static bool -descriptorWithoutRevisionEqual(const InternalServerDescriptorPtr& lhs, const InternalServerDescriptorPtr& rhs) +descriptorUpdated(const InternalServerDescriptorPtr& lhs, const InternalServerDescriptorPtr& rhs, bool noProps = false) { + if(lhs->uuid == rhs->uuid && lhs->revision == rhs->revision) + { + return false; + } + if(lhs->id != rhs->id || lhs->application != rhs->application || lhs->uuid != rhs->uuid || -// lhs->revision != rhs->revision || lhs->sessionId != rhs->sessionId || lhs->exe != rhs->exe || lhs->pwd != rhs->pwd || @@ -140,25 +144,25 @@ descriptorWithoutRevisionEqual(const InternalServerDescriptorPtr& lhs, const Int lhs->envs != rhs->envs || lhs->logs != rhs->logs) { - return false; + return true; } if((!lhs->distrib && rhs->distrib) || (lhs->distrib && !rhs->distrib)) { - return false; + return true; } else if(lhs->distrib && rhs->distrib) { if(lhs->distrib->icepatch != rhs->distrib->icepatch || lhs->distrib->directories != rhs->distrib->directories) { - return false; + return true; } } if(lhs->adapters.size() != rhs->adapters.size()) { - return false; + return true; } else { @@ -167,14 +171,14 @@ descriptorWithoutRevisionEqual(const InternalServerDescriptorPtr& lhs, const Int { if((*p)->id != (*q)->id || (*p)->serverLifetime != (*q)->serverLifetime) { - return false; + return true; } } } if(lhs->dbEnvs.size() != rhs->dbEnvs.size()) { - return false; + return true; } else { @@ -183,17 +187,40 @@ descriptorWithoutRevisionEqual(const InternalServerDescriptorPtr& lhs, const Int { if((*p)->name != (*q)->name || (*p)->properties != (*q)->properties) { - return false; + return true; } } } - if(lhs->properties != rhs->properties) + if(!noProps && lhs->properties != rhs->properties) { - return false; + return true; } - return true; + return false; +} + +Ice::PropertyDict +toPropertyDict(const PropertyDescriptorSeq& seq) +{ + Ice::PropertyDict props; + for(PropertyDescriptorSeq::const_iterator q = seq.begin(); q != seq.end(); ++q) + { + if(q->value.empty() && q->name.find('#') == 0) + { + continue; // Ignore comments. + } + + if(q->value.empty()) + { + props.erase(q->name); + } + else + { + props[q->name] = q->value; + } + } + return props; } class CommandTimeoutTimerTask : public IceUtil::TimerTask @@ -248,6 +275,109 @@ private: const TraceLevelsPtr _traceLevels; }; +class ResetPropertiesCB : public IceUtil::Shared +{ +public: + + ResetPropertiesCB(const ServerIPtr& server, + const Ice::ObjectPrx admin, + const InternalServerDescriptorPtr& desc, + const InternalServerDescriptorPtr& old, + const TraceLevelsPtr& traceLevels) : + _server(server), + _admin(admin), + _desc(desc), + _traceLevels(traceLevels), + _properties(server->getProperties(desc)), + _oldProperties(server->getProperties(old)), + _p(_properties.begin()) + { + } + + void + execute() + { + assert(_p != _properties.end()); + next(); + } + +private: + + void + next() + { + while(_p != _properties.end() && _p->second == _oldProperties[_p->first]) + { + ++_p; + } + if(_p == _properties.end()) + { + _server->updateRuntimePropertiesCallback(_desc); + return; + } + + Ice::PropertyDict oldProps = toPropertyDict(_oldProperties[_p->first]); + Ice::PropertyDict props = toPropertyDict(_p->second); + for(Ice::PropertyDict::const_iterator q = oldProps.begin(); q != oldProps.end(); ++q) + { + if(props.find(q->first) == props.end()) + { + props[q->first] = ""; + } + } + + string facet; + if(_p->first == "config") + { + facet = "Properties"; + if(_traceLevels->server > 1) + { + const string id = _server->getId(); + Ice::Trace out(_traceLevels->logger, _traceLevels->serverCat); + out << "updating runtime properties for server `" << id << "'"; + } + } + else + { + assert(_p->first.find("config_") == 0); + const string service = _p->first.substr(7); + facet = "IceBox.Service." + service + ".Properties"; + if(_traceLevels->server > 1) + { + const string id = _server->getId(); + Ice::Trace out(_traceLevels->logger, _traceLevels->serverCat); + out << "updating runtime properties for service `" << service << "' from server `" + id + "'"; + } + } + + // + // Increment the iterator *before* invoking setProperties_async to avoid a + // race condition. + // + ++_p; + + Ice::PropertiesAdminPrx p = Ice::PropertiesAdminPrx::uncheckedCast(_admin, facet); + p->begin_setProperties(props, Ice::newCallback_PropertiesAdmin_setProperties(this, + &ResetPropertiesCB::next, + &ResetPropertiesCB::exception)); + } + + void + exception(const Ice::Exception& ex) + { + _server->updateRuntimePropertiesCallback(ex, _desc); + } + + const ServerIPtr _server; + const Ice::ObjectPrx _admin; + const InternalServerDescriptorPtr _desc; + const TraceLevelsPtr _traceLevels; + const PropertyDescriptorSeqDict _properties; + PropertyDescriptorSeqDict _oldProperties; + PropertyDescriptorSeqDict::const_iterator _p; +}; +typedef IceUtil::Handle<ResetPropertiesCB> ResetPropertiesCBPtr; + struct EnvironmentEval : std::unary_function<string, string> { @@ -275,7 +405,8 @@ struct EnvironmentEval : std::unary_function<string, string> break; } string variable = v.substr(beg + 1, end - beg - 1); - DWORD ret = GetEnvironmentVariableW(IceUtil::stringToWstring(variable).c_str(), &buf[0], static_cast<DWORD>(buf.size())); + DWORD ret = GetEnvironmentVariableW(IceUtil::stringToWstring(variable).c_str(), &buf[0], + static_cast<DWORD>(buf.size())); string valstr = (ret > 0 && ret < buf.size()) ? IceUtil::wstringToString(&buf[0]) : string(""); v.replace(beg, end - beg + 1, valstr); beg += valstr.size(); @@ -354,8 +485,10 @@ TimedServerCommand::stopTimer() } } -LoadCommand::LoadCommand(const ServerIPtr& server) : - ServerCommand(server) +LoadCommand::LoadCommand(const ServerIPtr& server, + const InternalServerDescriptorPtr& runtime, + const TraceLevelsPtr& traceLevels) : + ServerCommand(server), _runtime(runtime), _updating(false), _traceLevels(traceLevels) { } @@ -403,12 +536,50 @@ LoadCommand::addCallback(const AMD_Node_loadServerPtr& amdCB) } void +LoadCommand::startRuntimePropertiesUpdate(const Ice::ObjectPrx& process) +{ + if(_updating) + { + return; + } + assert(_desc != _runtime); + _updating = true; + + ResetPropertiesCBPtr cb = new ResetPropertiesCB(_server, process, _desc, _runtime, _traceLevels); + cb->execute(); +} + +bool +LoadCommand::finishRuntimePropertiesUpdate(const InternalServerDescriptorPtr& runtime, const Ice::ObjectPrx& process) +{ + _updating = false; + _runtime = runtime; // The new runtime server descriptor. + + if(_traceLevels->server > 0) + { + Ice::Trace out(_traceLevels->logger, _traceLevels->serverCat); + out << "updated runtime properties for server `" << _server->getId() << "'"; + } + + if(_desc != _runtime) + { + startRuntimePropertiesUpdate(process); + return false; + } + else + { + return true; + } +} + +void LoadCommand::failed(const Ice::Exception& ex) { for(vector<AMD_Node_loadServerPtr>::const_iterator p = _loadCB.begin(); p != _loadCB.end(); ++p) { (*p)->ice_exception(ex); } + _loadCB.clear(); } void @@ -418,6 +589,7 @@ LoadCommand::finished(const ServerPrx& proxy, const AdapterPrxDict& adapters, in { (*p)->ice_response(proxy, adapters, at, dt); } + _loadCB.clear(); } DestroyCommand::DestroyCommand(const ServerIPtr& server, bool loadFailure, bool clearDir) : @@ -659,7 +831,7 @@ ServerI::ServerI(const NodeIPtr& node, const ServerPrx& proxy, const string& ser _disableOnFailure(0), _state(ServerI::Inactive), _activation(ServerI::Disabled), - _failureTime(IceUtil::Time::now(IceUtil::Time::Monotonic)), // Ensure that _activation gets initialized in updateImpl(). + _failureTime(IceUtil::Time::now(IceUtil::Time::Monotonic)), // Ensure that _activation is init. in updateImpl(). _pid(0) { assert(_node->getActivator()); @@ -1040,7 +1212,8 @@ ServerI::start(ServerActivation activation, const AMD_Server_startPtr& amdCB) } ServerCommandPtr -ServerI::load(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescriptorPtr& desc, const string& replicaName) +ServerI::load(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescriptorPtr& desc, const string& replicaName, + bool noRestart) { Lock sync(*this); checkDestroyed(); @@ -1056,12 +1229,10 @@ ServerI::load(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescripto // we don't re-load the server. We just return the server // proxy and the proxies of its adapters. // - if(_desc && - (replicaName != "Master" || _desc->sessionId == desc->sessionId) && - ((_desc->uuid == desc->uuid && _desc->revision == desc->revision) || - descriptorWithoutRevisionEqual(_desc, desc))) + InternalServerDescriptorPtr d = _load ? _load->getInternalServerDescriptor() : _desc; + if(d && (replicaName != "Master" || d->sessionId == desc->sessionId) && !descriptorUpdated(d, desc)) { - if(_desc->revision != desc->revision) + if(d->revision != desc->revision) { updateRevision(desc->uuid, desc->revision); } @@ -1078,13 +1249,27 @@ ServerI::load(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescripto return 0; } - if(!StopCommand::isStopped(_state) && !_stop) + if(!StopCommand::isStopped(_state) && !_stop) // Server is running and no stop is scheduled { - _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout); + assert(_desc); + if(noRestart) + { + // + // If the server is not inactive, we have to make sure the update doesn't require + // a restart. If it requires a restart, we throw. Otherwise we update its properties + // now. + // + checkNoRestart(desc); + } + else + { + _stop = new StopCommand(this, _node->getTimer(), _deactivationTimeout); + } } + if(!_load) { - _load = new LoadCommand(this); + _load = new LoadCommand(this, _desc, _node->getTraceLevels()); } _load->setUpdate(desc, _destroy); if(_destroy && _state != Destroying) @@ -1092,13 +1277,64 @@ ServerI::load(const AMD_Node_loadServerPtr& amdCB, const InternalServerDescripto _destroy->finished(); _destroy = 0; } + if(amdCB) { _load->addCallback(amdCB); } + + if(!_stop && _state == Active) // Must be done after adding the AMD callback. + { + updateRevision(desc->uuid, desc->revision); + _load->startRuntimePropertiesUpdate(_process); + } return nextCommand(); } +bool +ServerI::checkUpdate(const InternalServerDescriptorPtr& desc, bool noRestart, const Ice::Current&) +{ + Lock sync(*this); + checkDestroyed(); + + if(!_desc) + { + throw DeploymentException("server not loaded"); + } + + InternalServerDescriptorPtr d = _load ? _load->getInternalServerDescriptor() : _desc; + if(!descriptorUpdated(d, desc)) + { + return StopCommand::isStopped(_state); + } + + if(noRestart) + { + checkNoRestart(desc); + } + + try + { + checkAndUpdateUser(desc, false); // false = don't update the user, just check. + } + catch(const Ice::Exception& ex) + { + ostringstream os; + os << ex; + throw DeploymentException(os.str()); + } + catch(const string& msg) + { + throw DeploymentException(msg); + } + catch(const char* msg) + { + throw DeploymentException(msg); + } + + return StopCommand::isStopped(_state); +} + ServerCommandPtr ServerI::destroy(const AMD_Node_destroyServerPtr& amdCB, const string& uuid, int revision, const string& replicaName) { @@ -1785,6 +2021,12 @@ ServerI::update() _node->removeServer(this, oldDescriptor->application); _node->addServer(this, _desc->application); } + + if(_node->getTraceLevels()->server > 0) + { + Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat); + out << "updated configuration for server `" << _id << "'"; + } } else { @@ -1948,116 +2190,7 @@ ServerI::updateImpl(const InternalServerDescriptorPtr& descriptor) _timerTask = 0; } -#ifndef _WIN32 - _uid = getuid(); - _gid = getgid(); -#endif - - // - // Don't change the user if the server has the session activation - // mode and if it's not currently owned by a session. - // - string user; - if(_desc->activation != "session" || !_desc->sessionId.empty()) - { - user = _desc->user; -#ifndef _WIN32 - // - // Check if the node is running as root, if that's the case we - // make sure that a user is set for the process. - // - if(_uid == 0 && user.empty()) - { - // - // If no user is configured and if this server is owned by - // a session we set the user to the session id, otherwise - // we set it to "nobody". - // - user = !_desc->sessionId.empty() ? _desc->sessionId : "nobody"; - } -#endif - } - - if(!user.empty()) - { - UserAccountMapperPrx mapper = _node->getUserAccountMapper(); - if(mapper) - { - try - { - user = mapper->getUserAccount(user); - } - catch(const UserAccountNotFoundException&) - { - throw "couldn't find user account for user `" + user + "'"; - } - catch(const Ice::LocalException& ex) - { - ostringstream os; - os << "unexpected exception while trying to find user account for user `" << user << "':\n" << ex; - throw os.str(); - } - } - -#ifdef _WIN32 - // - // Windows doesn't support running processes under another - // account (at least not easily, see the CreateProcessAsUser - // documentation). So if a user is specified, we just check - // that the node is running under the same user account as the - // one which is specified. - // - vector<char> buf(256); - buf.resize(256); - DWORD size = static_cast<DWORD>(buf.size()); - bool success = GetUserName(&buf[0], &size); - if(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - buf.resize(size); - success = GetUserName(&buf[0], &size); - } - if(!success) - { - Ice::SyscallException ex(__FILE__, __LINE__); - ex.error = IceInternal::getSystemErrno(); - throw ex; - } - if(user != string(&buf[0])) - { - throw "couldn't load server under user account `" + user + "': feature not supported on Windows"; - } -#else - // - // Get the uid/gid associated with the given user. - // - struct passwd* pw = getpwnam(user.c_str()); - if(!pw) - { - throw "unknown user account `" + user + "'"; - } - - // - // If the node isn't running as root and if the uid of the - // configured user is different from the uid of the userr - // running the node we throw, a regular user can't run a - // process as another user. - // - if(_uid != 0 && pw->pw_uid != _uid) - { - throw "node has insufficient privileges to load server under user account `" + user + "'"; - } - - - if(pw->pw_uid == 0 && - _node->getCommunicator()->getProperties()->getPropertyAsInt("IceGrid.Node.AllowRunningServersAsRoot") == 0) - { - throw "running server as `root' is not allowed"; - } - - _uid = pw->pw_uid; - _gid = pw->pw_gid; -#endif - } + checkAndUpdateUser(_desc, true); // we pass true to update _uid/_gid. istringstream at(_desc->activationTimeout); if(!(at >> _activationTimeout) || !at.eof() || _activationTimeout == 0) @@ -2088,58 +2221,10 @@ ServerI::updateImpl(const InternalServerDescriptorPtr& descriptor) } sort(_logs.begin(), _logs.begin()); - // - // Copy the descriptor properties. We shouldn't modify the - // descriptor since it's used for the comparison when the server - // needs to be updated. - // - PropertyDescriptorSeqDict properties = _desc->properties; + PropertyDescriptorSeqDict properties = getProperties(_desc); PropertyDescriptorSeq& props = properties["config"]; - - // - // Cache the path of the stderr/stdout file, first check if the - // node OutputDir property is set and then we check the server - // configuration file for the Ice.StdErr and Ice.StdOut - // properties. - // _stdErrFile = getProperty(props, "Ice.StdErr"); _stdOutFile = getProperty(props, "Ice.StdOut"); - string outputDir = _node->getOutputDir(); - if(!outputDir.empty()) - { - if(_stdErrFile.empty()) - { - _stdErrFile = outputDir + "/" + _id + (_node->getRedirectErrToOut() ? ".out" : ".err"); - props.push_back(createProperty("Ice.StdErr", _stdErrFile)); - } - if(_stdOutFile.empty()) - { - _stdOutFile = outputDir + "/" + _id + ".out"; - props.push_back(createProperty("Ice.StdOut", _stdOutFile)); - } - } - - // - // Add the locator proxy property and the node properties override - // - { - const PropertyDescriptorSeq& overrides = _node->getPropertiesOverride(); - for(PropertyDescriptorSeqDict::iterator p = properties.begin(); p != properties.end(); ++p) - { - if(getProperty(p->second, "Ice.Default.Locator").empty()) - { - p->second.push_back( - createProperty("Ice.Default.Locator", - _node->getCommunicator()->getProperties()->getProperty("Ice.Default.Locator"))); - } - - if(!overrides.empty()) - { - p->second.push_back(createProperty("# Node properties override")); - p->second.insert(p->second.end(), overrides.begin(), overrides.end()); - } - } - } // // If the server is a session server and it wasn't udpated but @@ -2298,7 +2383,12 @@ ServerI::checkRevision(const string& replicaName, const string& uuid, int revisi string descUUID; int descRevision; - if(_desc) + if(_load) + { + descUUID = _load->getInternalServerDescriptor()->uuid; + descRevision = _load->getInternalServerDescriptor()->revision; + } + else if(_desc) { descUUID = _desc->uuid; descRevision = _desc->revision; @@ -2338,11 +2428,157 @@ ServerI::checkRevision(const string& replicaName, const string& uuid, int revisi } void +ServerI::checkNoRestart(const InternalServerDescriptorPtr& desc) +{ + assert(_desc); + + if(_desc->sessionId != desc->sessionId) + { + throw DeploymentException("server allocated by another session"); + } + + if(descriptorUpdated(_desc, desc, true)) // true = ignore properties + { + throw DeploymentException("update requires server to be stopped"); + } +} + +void +ServerI::checkAndUpdateUser(const InternalServerDescriptorPtr& desc, bool update) +{ +#ifndef _WIN32 + uid_t uid = getuid(); + uid_t gid = getgid(); +#endif + + // + // Don't change the user if the server has the session activation + // mode and if it's not currently owned by a session. + // + string user; + if(desc->activation != "session" || !desc->sessionId.empty()) + { + user = desc->user; +#ifndef _WIN32 + // + // Check if the node is running as root, if that's the case we + // make sure that a user is set for the process. + // + if(uid == 0 && user.empty()) + { + // + // If no user is configured and if this server is owned by + // a session we set the user to the session id, otherwise + // we set it to "nobody". + // + user = !desc->sessionId.empty() ? desc->sessionId : "nobody"; + } +#endif + } + + if(!user.empty()) + { + UserAccountMapperPrx mapper = _node->getUserAccountMapper(); + if(mapper) + { + try + { + user = mapper->getUserAccount(user); + } + catch(const UserAccountNotFoundException&) + { + throw "couldn't find user account for user `" + user + "'"; + } + catch(const Ice::LocalException& ex) + { + ostringstream os; + os << "unexpected exception while trying to find user account for user `" << user << "':\n" << ex; + throw os.str(); + } + } + +#ifdef _WIN32 + // + // Windows doesn't support running processes under another + // account (at least not easily, see the CreateProcessAsUser + // documentation). So if a user is specified, we just check + // that the node is running under the same user account as the + // one which is specified. + // + vector<char> buf(256); + buf.resize(256); + DWORD size = static_cast<DWORD>(buf.size()); + bool success = GetUserName(&buf[0], &size); + if(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + buf.resize(size); + success = GetUserName(&buf[0], &size); + } + if(!success) + { + Ice::SyscallException ex(__FILE__, __LINE__); + ex.error = IceInternal::getSystemErrno(); + throw ex; + } + if(user != string(&buf[0])) + { + throw "couldn't load server under user account `" + user + "': feature not supported on Windows"; + } + } +#else + // + // Get the uid/gid associated with the given user. + // + struct passwd* pw = getpwnam(user.c_str()); + if(!pw) + { + throw "unknown user account `" + user + "'"; + } + + // + // If the node isn't running as root and if the uid of the + // configured user is different from the uid of the userr + // running the node we throw, a regular user can't run a + // process as another user. + // + if(uid != 0 && pw->pw_uid != uid) + { + throw "node has insufficient privileges to load server under user account `" + user + "'"; + } + + + if(pw->pw_uid == 0 && + _node->getCommunicator()->getProperties()->getPropertyAsInt("IceGrid.Node.AllowRunningServersAsRoot") == 0) + { + throw "running server as `root' is not allowed"; + } + + if(update) + { + _uid = pw->pw_uid; + _gid = pw->pw_gid; + } + } + else if(update) + { + _uid = uid; + _gid = gid; + } +#endif +} + +void ServerI::updateRevision(const string& uuid, int revision) { _desc->uuid = uuid; _desc->revision = revision; + if(_load) + { + _load->getInternalServerDescriptor()->uuid = uuid; + _load->getInternalServerDescriptor()->revision = revision; + } + string idFilePath = _serverDir + "/revision"; IceUtilInternal::ofstream os(idFilePath); // idFilePath is a UTF-8 string if(os.good()) @@ -2355,6 +2591,41 @@ ServerI::updateRevision(const string& uuid, int revision) } } +void +ServerI::updateRuntimePropertiesCallback(const InternalServerDescriptorPtr& desc) +{ + Lock sync(*this); + if(_state != Active || !_load) + { + return; + } + + if(_load->finishRuntimePropertiesUpdate(desc, _process)) + { + AdapterPrxDict adapters; + for(ServerAdapterDict::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p) + { + adapters.insert(make_pair(p->first, p->second->getProxy())); + } + _load->finished(_this, adapters, _activationTimeout, _deactivationTimeout); + } +} + +void +ServerI::updateRuntimePropertiesCallback(const Ice::Exception& ex, const InternalServerDescriptorPtr& desc) +{ + Lock sync(*this); + if(_state != Active || !_load) + { + return; + } + + if(_load->finishRuntimePropertiesUpdate(desc, _process)) + { + _load->failed(ex); + } +} + bool ServerI::checkActivation() { @@ -2469,7 +2740,6 @@ ServerI::setStateNoSync(InternalServerState st, const std::string& reason) // InternalServerState previous = _state; _state = st; - // // Check if some commands are done. @@ -2617,6 +2887,14 @@ ServerI::setStateNoSync(InternalServerState st, const std::string& reason) } } } + else if(_state == Active && _load) + { + // + // If there's a pending load command, it's time to update the + // runtime properties of the server now that it's active. + // + _load->startRuntimePropertiesUpdate(_process); + } // // Don't send the server update if the state didn't change or if @@ -2641,8 +2919,11 @@ ServerI::setStateNoSync(InternalServerState st, const std::string& reason) } else if(_state == ServerI::Inactive) { - Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat); - out << "changed server `" << _id << "' state to `Inactive'"; + if(_node->getTraceLevels()->server != 2 && !(previous == ServerI::Loading || previous == ServerI::Patching)) + { + Ice::Trace out(_node->getTraceLevels()->logger, _node->getTraceLevels()->serverCat); + out << "changed server `" << _id << "' state to `Inactive'"; + } } else if(_state == ServerI::Destroyed) { @@ -2819,3 +3100,59 @@ ServerI::getFilePath(const string& filename) const } } +PropertyDescriptorSeqDict +ServerI::getProperties(const InternalServerDescriptorPtr& desc) +{ + // + // Copy the descriptor properties. + // + PropertyDescriptorSeqDict properties = desc->properties; + PropertyDescriptorSeq& props = properties["config"]; + + // + // Cache the path of the stderr/stdout file, first check if the + // node OutputDir property is set and then we check the server + // configuration file for the Ice.StdErr and Ice.StdOut + // properties. + // + string stdErrFile = getProperty(props, "Ice.StdErr"); + string stdOutFile = getProperty(props, "Ice.StdOut"); + string outputDir = _node->getOutputDir(); + if(!outputDir.empty()) + { + if(stdErrFile.empty()) + { + stdErrFile = outputDir + "/" + _id + (_node->getRedirectErrToOut() ? ".out" : ".err"); + props.push_back(createProperty("Ice.StdErr", stdErrFile)); + } + if(stdOutFile.empty()) + { + stdOutFile = outputDir + "/" + _id + ".out"; + props.push_back(createProperty("Ice.StdOut", stdOutFile)); + } + } + + // + // Add the locator proxy property and the node properties override + // + { + const PropertyDescriptorSeq& overrides = _node->getPropertiesOverride(); + for(PropertyDescriptorSeqDict::iterator p = properties.begin(); p != properties.end(); ++p) + { + if(getProperty(p->second, "Ice.Default.Locator").empty()) + { + p->second.push_back( + createProperty("Ice.Default.Locator", + _node->getCommunicator()->getProperties()->getProperty("Ice.Default.Locator"))); + } + + if(!overrides.empty()) + { + p->second.push_back(createProperty("# Node properties override")); + p->second.insert(p->second.end(), overrides.begin(), overrides.end()); + } + } + } + + return properties; +} diff --git a/cpp/src/IceGrid/ServerI.h b/cpp/src/IceGrid/ServerI.h index e40cd51c877..b86d611bf7a 100644 --- a/cpp/src/IceGrid/ServerI.h +++ b/cpp/src/IceGrid/ServerI.h @@ -94,7 +94,8 @@ public: bool dependsOnApplicationDistrib() const; void start(ServerActivation, const AMD_Server_startPtr& = AMD_Server_startPtr()); - ServerCommandPtr load(const AMD_Node_loadServerPtr&, const InternalServerDescriptorPtr&, const std::string&); + ServerCommandPtr load(const AMD_Node_loadServerPtr&, const InternalServerDescriptorPtr&, const std::string&, bool); + bool checkUpdate(const InternalServerDescriptorPtr&, bool, const Ice::Current&); ServerCommandPtr destroy(const AMD_Node_destroyServerPtr&, const std::string&, int, const std::string&); bool startPatch(bool); bool waitForPatch(); @@ -117,10 +118,17 @@ public: // Ice::ObjectPrx getProcess() const; + PropertyDescriptorSeqDict getProperties(const InternalServerDescriptorPtr&); + + void updateRuntimePropertiesCallback(const InternalServerDescriptorPtr&); + void updateRuntimePropertiesCallback(const Ice::Exception&, const InternalServerDescriptorPtr&); + private: void updateImpl(const InternalServerDescriptorPtr&); void checkRevision(const std::string&, const std::string&, int) const; + void checkNoRestart(const InternalServerDescriptorPtr&); + void checkAndUpdateUser(const InternalServerDescriptorPtr&, bool); void updateRevision(const std::string&, int); bool checkActivation(); void checkDestroyed() const; @@ -299,7 +307,7 @@ class LoadCommand : public ServerCommand { public: - LoadCommand(const ServerIPtr&); + LoadCommand(const ServerIPtr&, const InternalServerDescriptorPtr&, const TraceLevelsPtr&); bool canExecute(ServerI::InternalServerState); ServerI::InternalServerState nextState(); @@ -309,6 +317,8 @@ public: bool clearDir() const; InternalServerDescriptorPtr getInternalServerDescriptor() const; void addCallback(const AMD_Node_loadServerPtr&); + void startRuntimePropertiesUpdate(const Ice::ObjectPrx&); + bool finishRuntimePropertiesUpdate(const InternalServerDescriptorPtr&, const Ice::ObjectPrx&); void failed(const Ice::Exception&); void finished(const ServerPrx&, const AdapterPrxDict&, int, int); @@ -317,6 +327,9 @@ private: std::vector<AMD_Node_loadServerPtr> _loadCB; bool _clearDir; InternalServerDescriptorPtr _desc; + InternalServerDescriptorPtr _runtime; + bool _updating; + TraceLevelsPtr _traceLevels; std::auto_ptr<DeploymentException> _exception; }; |