diff --git a/Source/Thunder/Config.h b/Source/Thunder/Config.h index d3fc8f160..9152bdd4b 100644 --- a/Source/Thunder/Config.h +++ b/Source/Thunder/Config.h @@ -114,64 +114,6 @@ namespace PluginHost { // Configuration to get a server (PluginHost server) up and running. class JSONConfig : public Core::JSON::Container { public: - class Environment : public Core::JSON::Container { - public: - Environment() - : Core::JSON::Container() - , Key() - , Value() - , Override(false) - { - Add(_T("key"), &Key); - Add(_T("value"), &Value); - Add(_T("override"), &Override); - } - Environment(const Environment& copy) - : Core::JSON::Container() - , Key(copy.Key) - , Value(copy.Value) - , Override(copy.Override) - { - Add(_T("key"), &Key); - Add(_T("value"), &Value); - Add(_T("override"), &Override); - } - Environment(Environment&& move) noexcept - : Core::JSON::Container() - , Key(std::move(move.Key)) - , Value(std::move(move.Value)) - , Override(std::move(move.Override)) - { - Add(_T("key"), &Key); - Add(_T("value"), &Value); - Add(_T("override"), &Override); - } - ~Environment() override = default; - Environment& operator=(const Environment& RHS) - { - Key = RHS.Key; - Value = RHS.Value; - Override = RHS.Override; - - return (*this); - } - Environment& operator=(Environment&& move) noexcept - { - if (this != &move) { - Key = std::move(move.Key); - Value = std::move(move.Value); - Override = std::move(move.Override); - } - - return (*this); - } - - public: - Core::JSON::String Key; - Core::JSON::String Value; - Core::JSON::Boolean Override; - }; - class ProcessSet : public Core::JSON::Container { public: ProcessSet() @@ -526,7 +468,7 @@ namespace PluginHost { Core::JSON::String Configs; Core::JSON::String EthernetCard; Core::JSON::ArrayType Plugins; - Core::JSON::ArrayType Environments; + Core::JSON::ArrayType Environments; Core::JSON::ArrayType> ExitReasons; Core::JSON::DecSInt32 Latitude; Core::JSON::DecSInt32 Longitude; @@ -773,12 +715,12 @@ namespace PluginHost { } bool status = true; - Core::JSON::ArrayType::ConstIterator index(static_cast(config).Environments.Elements()); + Core::JSON::ArrayType::ConstIterator index(static_cast(config).Environments.Elements()); while (index.Next() == true) { if ((index.Current().Key.IsSet() == true) && (index.Current().Value.IsSet() == true)) { string value = _substituter.Substitute(index.Current().Value.Value(), nullptr); if (value.empty() != true) { - status = Core::SystemInfo::SetEnvironment(index.Current().Key.Value(), value, index.Current().Override.Value()); + status = Core::SystemInfo::SetEnvironment(index.Current().Key.Value(), value, ((index.Current().Override.Value() == RPC::Object::Environment::Scope::GLOBAL) ? true : false)); if (status != true) { SYSLOG(Logging::Startup, (_T("Failure in setting Key:Value:[%s]:[%s]\n"), index.Current().Key.Value().c_str(), index.Current().Value.Value().c_str())); } diff --git a/Source/Thunder/IRemoteInstantiation.h b/Source/Thunder/IRemoteInstantiation.h index f3249295b..169bb4a0a 100644 --- a/Source/Thunder/IRemoteInstantiation.h +++ b/Source/Thunder/IRemoteInstantiation.h @@ -27,6 +27,7 @@ namespace PluginHost { struct IRemoteInstantiation : virtual public Core::IUnknown { enum { ID = RPC::IDS::ID_REMOTE_INSTANTIATION }; + using IEnvironmentIterator = RPC::IIteratorType; ~IRemoteInstantiation() override = default; @@ -56,7 +57,8 @@ namespace PluginHost { const string& systemRootPath, const uint8_t threads, const int8_t priority, - const string configuration) = 0; + const string configuration, + IEnvironmentIterator* const& environments) = 0; }; } } diff --git a/Source/Thunder/PluginServer.h b/Source/Thunder/PluginServer.h index 6d1b72ad5..5d6af136a 100644 --- a/Source/Thunder/PluginServer.h +++ b/Source/Thunder/PluginServer.h @@ -377,6 +377,8 @@ namespace PluginHost { DYNAMIC }; + using Services = std::unordered_map; + private: using BaseClass = PluginHost::Service; using Jobs = Core::ThrottleQueueType, ServiceMap&>; @@ -1277,16 +1279,29 @@ namespace PluginHost { string Substitute(const string& input) const override { return (_administrator.Configuration().Substitute(input, PluginHost::Service::Configuration())); } - Core::hresult Metadata(string& info /* @out */) const override { + Core::hresult Metadata(string& info /* @out */) const override { Metadata::Service result; GetMetadata(result); result.ToString(info); return (Core::ERROR_NONE); } + std::vector& SubstituteList(const std::vector& environmentList) const { + std::vector& environments = const_cast&>(environmentList); + for (auto& environment : environments) { + if ((environment.key.empty() != true) && (environment.value.empty() != true)) { + environment.value = Substitute(environment.value); + } else { + SYSLOG(Logging::Startup, (_T("Failure in Substituting Value of Key:Value:[%s]:[%s]\n"), environment.key.c_str(), environment.value.c_str())); + } + } + return environments; + } void* Instantiate(const RPC::Object& object, const uint32_t waitTime, uint32_t& sessionId) override { ASSERT(_connection == nullptr); + const_cast(object).Environments(SubstituteList(object.Environments())); + void* result(_administrator.Instantiate(object, waitTime, sessionId, DataPath(), PersistentPath(), VolatilePath(), _administrator.Configuration().LinkerPluginPaths())); if (result != nullptr) { @@ -1499,7 +1514,9 @@ namespace PluginHost { else { uint32_t pid; Core::ServiceAdministrator::Instance().ReleaseLibrary(std::move(_library)); - + string environments; + PluginHost::Service::Configuration().Root.Environments.ToString(environments); + RPC::Object definition(locator, classNameString, Callsign(), @@ -1512,7 +1529,8 @@ namespace PluginHost { PluginHost::Service::Configuration().Root.HostType(), SystemRootPath(), PluginHost::Service::Configuration().Root.RemoteAddress.Value(), - PluginHost::Service::Configuration().Root.Configuration.Value()); + PluginHost::Service::Configuration().Root.Configuration.Value(), + Plugin::Config::Environment::List(PluginHost::Service::Configuration().Root.Environments)); newIF = reinterpret_cast(Instantiate(definition, _administrator.Configuration().OutOfProcessWaitTime(), pid)); if (newIF == nullptr) { @@ -2007,6 +2025,10 @@ namespace PluginHost { if (instantiation == nullptr) { result = Core::ERROR_ILLEGAL_STATE; } else { + + using Iterator = IRemoteInstantiation::IEnvironmentIterator; + Iterator* environment = Core::Service>::Create(_object.Environments()); + result = instantiation->Instantiate( RPC::Communicator::RemoteConnection::Id(), _object.Locator(), @@ -2019,7 +2041,8 @@ namespace PluginHost { _object.SystemRootPath(), _object.Threads(), _object.Priority(), - _object.Configuration()); + _object.Configuration(), + environment); instantiation->Release(); } @@ -2399,7 +2422,8 @@ namespace PluginHost { const string& systemRootPath, const uint8_t threads, const int8_t priority, - const string configuration) override + const string configuration, + IRemoteInstantiation::IEnvironmentIterator* const& environments) override { string persistentPath(_comms.PersistentPath()); string dataPath(_comms.DataPath()); @@ -2411,10 +2435,17 @@ namespace PluginHost { volatilePath += callsign + '/'; } + std::vector _environmentList; + if (environments != nullptr) { + RPC::Object::Environment environment; + while (environments->Next(environment) == true) { + _environmentList.push_back(environment); + } + } + uint32_t id; RPC::Config config(_connector, _comms.Application(), persistentPath, _comms.SystemPath(), dataPath, volatilePath, _comms.AppPath(), _comms.ProxyStubPath(), _comms.PostMortemPath(), _comms.LinkerPaths()); - RPC::Object instance(libraryName, className, callsign, interfaceId, version, user, group, threads, priority, RPC::Object::HostType::LOCAL, systemRootPath, _T(""), configuration); - + RPC::Object instance(libraryName, className, callsign, interfaceId, version, user, group, threads, priority, RPC::Object::HostType::LOCAL, systemRootPath, _T(""), configuration, SubstituteList(callsign, _environmentList)); RPC::Communicator::Process process(requestId, config, instance); return (process.Launch(id)); @@ -2424,6 +2455,16 @@ namespace PluginHost { INTERFACE_ENTRY(IRemoteInstantiation) END_INTERFACE_MAP + private: + std::vector& SubstituteList(const string& callsign, std::vector& environments) const + { + Core::ProxyType service = _parent.GetService(callsign); + if (service.IsValid() == true) { + environments = service->SubstituteList(environments); + } + return environments; + } + private: mutable uint32_t _refCount; ServiceMap& _parent; @@ -3064,6 +3105,17 @@ namespace PluginHost { _adminLock.Unlock(); } + inline Core::ProxyType GetService(const string& callsign) + { + Core::ProxyType service; + for (std::pair>& entry : _services) { + if (entry.first == callsign) { + service = entry.second; + break; + } + } + return service; + } inline Iterator Services() { Shells workingList; diff --git a/Source/ThunderPlugin/Process.cpp b/Source/ThunderPlugin/Process.cpp index df3d64432..e7cab38c8 100644 --- a/Source/ThunderPlugin/Process.cpp +++ b/Source/ThunderPlugin/Process.cpp @@ -159,7 +159,7 @@ POP_WARNING() class ConsoleOptions : public Core::Options { public: ConsoleOptions(int argumentCount, TCHAR* arguments[]) - : Core::Options(argumentCount, arguments, _T("h:l:c:C:r:p:s:d:a:m:i:u:g:t:e:x:V:v:P:S:f:")) + : Core::Options(argumentCount, arguments, _T("h:l:c:C:r:p:s:d:a:m:i:u:g:t:e:E:x:V:v:P:S:f:")) , Locator(nullptr) , ClassName(nullptr) , Callsign(nullptr) @@ -202,6 +202,7 @@ POP_WARNING() string ProxyStubPath; string PostMortemPath; string SystemRootPath; + std::vector Environments; const TCHAR* User; const TCHAR* Group; uint8_t Threads; @@ -250,6 +251,13 @@ POP_WARNING() case 'S': SystemRootPath = Core::Directory::Normalize(Strip(argument)); break; + case 'e': + case 'E': { + Environments.push_back(Plugin::Config::Environment::Info(Strip(argument), + ((option == 'E') ? RPC::Object::Environment::Scope::GLOBAL : + RPC::Object::Environment::Scope::LOCAL))); + break; + } case 'v': VolatilePath = Core::Directory::Normalize(Strip(argument)); break; @@ -588,6 +596,8 @@ int main(int argc, char** argv) printf(" [-d ]\n"); printf(" [-v ]\n"); printf(" [-f ...\n"); + printf(" [-e/-E ...]\n"); + printf(" e: means set as local scope, E: means set as global scope\n"); printf(" [-a ]\n"); printf(" [-m ]\n"); printf(" [-P ]\n\n"); @@ -664,6 +674,15 @@ int main(int argc, char** argv) Core::ProcessCurrent().User(string(options.User)); } + for (const auto& info : options.Environments) { + if ((info.key.empty() != true) && (info.value.empty() != true)) { + uint32_t status = Core::SystemInfo::SetEnvironment(info.key, info.value.c_str(), ((info.overriding == RPC::Object::Environment::Scope::GLOBAL) ? true : false)); + if (status != true) { + SYSLOG(Logging::Startup, (_T("Failure in setting Key:Value:[%s]:[%s]\n"), info.key.c_str(), info.value.c_str())); + } + } + } + process.Startup(options.Threads, remoteNode, callsign); // Register an interface to handle incoming requests for interfaces. diff --git a/Source/com/Communicator.cpp b/Source/com/Communicator.cpp index 266c64772..e8efcac3d 100644 --- a/Source/com/Communicator.cpp +++ b/Source/com/Communicator.cpp @@ -575,4 +575,12 @@ namespace RPC { constexpr uint32_t RPC::ProcessShutdown::DestructionStackSize; } + +ENUM_CONVERSION_BEGIN(RPC::Object::Environment::Scope) + + { RPC::Object::Environment::Scope::LOCAL, _TXT("Local") }, + { RPC::Object::Environment::Scope::GLOBAL, _TXT("Global") }, + +ENUM_CONVERSION_END(RPC::Object::Environment::Scope) + } diff --git a/Source/com/Communicator.h b/Source/com/Communicator.h index 054a8644b..085e3b237 100644 --- a/Source/com/Communicator.h +++ b/Source/com/Communicator.h @@ -45,12 +45,23 @@ namespace RPC { class EXTERNAL Object { public: + static constexpr const TCHAR EnvironmentSeparator = _T('='); enum class HostType { LOCAL, DISTRIBUTED, CONTAINER }; + struct Environment { + enum class Scope { + LOCAL, + GLOBAL + }; + string key; + string value; + Scope overriding; + }; + Object() : _locator() , _className() @@ -65,6 +76,7 @@ namespace RPC { , _systemRootPath() , _remoteAddress() , _configuration() + , _environments() { } Object(const Object& copy) @@ -81,6 +93,7 @@ namespace RPC { , _systemRootPath(copy._systemRootPath) , _remoteAddress(copy._remoteAddress) , _configuration(copy._configuration) + , _environments(copy._environments) { } Object(Object&& move) noexcept @@ -97,6 +110,7 @@ namespace RPC { , _systemRootPath(std::move(move._systemRootPath)) , _remoteAddress(std::move(move._remoteAddress)) , _configuration(std::move(move._configuration)) + , _environments(std::move(move._environments)) { } Object(const string& locator, @@ -111,7 +125,8 @@ namespace RPC { const HostType type, const string& systemRootPath, const string& remoteAddress, - const string& configuration) + const string& configuration, + const std::vector& environments) : _locator(locator) , _className(className) , _callsign(callsign) @@ -125,6 +140,7 @@ namespace RPC { , _systemRootPath(systemRootPath) , _remoteAddress(remoteAddress) , _configuration(configuration) + , _environments(environments) { } ~Object() @@ -146,6 +162,7 @@ namespace RPC { _type = RHS._type; _remoteAddress = RHS._remoteAddress; _configuration = RHS._configuration; + _environments = RHS._environments; return (*this); } @@ -166,6 +183,7 @@ namespace RPC { _systemRootPath = std::move(move._systemRootPath); _remoteAddress = std::move(move._remoteAddress); _configuration = std::move(move._configuration); + _environments = std::move(move._environments); move._interface = ~0; move._version = ~0; @@ -228,6 +246,13 @@ namespace RPC { { return (_configuration); } + inline const std::vector& Environments() const + { + return (_environments); + } + inline void Environments(const std::vector& environments) { + _environments = std::move(environments); + } private: string _locator; @@ -243,6 +268,7 @@ namespace RPC { string _systemRootPath; string _remoteAddress; string _configuration; + std::vector _environments; }; class EXTERNAL Config { @@ -300,7 +326,7 @@ namespace RPC { , _linker(copy._linker) { } - Config(Config&& move) noexcept + Config(Config&& move) noexcept : _connector(std::move(move._connector)) , _hostApplication(std::move(move._hostApplication)) , _persistent(std::move(move._persistent)) @@ -515,6 +541,12 @@ namespace RPC { if (instance.Threads() > 1) { _options.Add(_T("-t")).Add(Core::NumberType(instance.Threads()).Text()); } + for (auto const& environment : instance.Environments()) { + string env = environment.key + RPC::Object::EnvironmentSeparator + + "\"" + environment.value + "\""; + string option = (environment.overriding == RPC::Object::Environment::Scope::GLOBAL) ? "-E" : "-e"; + _options.Add(_T(option)).Add('"' + env + '"'); + } _priority = instance.Priority(); } const string& Command() const diff --git a/Source/com/Ids.h b/Source/com/Ids.h index 9c387bdbb..6c1a3b07d 100644 --- a/Source/com/Ids.h +++ b/Source/com/Ids.h @@ -89,6 +89,7 @@ namespace RPC { ID_SUBSYSTEM_DECRYPTION = (ID_OFFSET_INTERNAL + 0x003E), ID_REMOTE_INSTANTIATION = (ID_OFFSET_INTERNAL + 0x003F), ID_SYSTEM_METADATA = (ID_OFFSET_INTERNAL + 0x0040), + ID_ENVIRONMENT_ITERATOR = (ID_OFFSET_INTERNAL + 0x0041), ID_EXTERNAL_INTERFACE_OFFSET = (ID_OFFSET_INTERNAL + 0x0080), ID_EXTERNAL_QA_INTERFACE_OFFSET = (ID_OFFSET_INTERNAL + 0xA000) diff --git a/Source/plugins/Configuration.h b/Source/plugins/Configuration.h index 3bbf40d04..325f6ed6d 100644 --- a/Source/plugins/Configuration.h +++ b/Source/plugins/Configuration.h @@ -34,6 +34,106 @@ namespace Plugin { */ class EXTERNAL Config : public Core::JSON::Container { public: + class Environment : public Core::JSON::Container { + public: + Environment() + : Core::JSON::Container() + , Key() + , Value() + , Override(RPC::Object::Environment::Scope::LOCAL) + { + Add(_T("key"), &Key); + Add(_T("value"), &Value); + Add(_T("override"), &Override); + } + Environment(const Environment& copy) + : Core::JSON::Container() + , Key(copy.Key) + , Value(copy.Value) + , Override(copy.Override) + { + Add(_T("key"), &Key); + Add(_T("value"), &Value); + Add(_T("override"), &Override); + } + Environment(Environment&& move) noexcept + : Core::JSON::Container() + , Key(std::move(move.Key)) + , Value(std::move(move.Value)) + , Override(std::move(move.Override)) + { + Add(_T("key"), &Key); + Add(_T("value"), &Value); + Add(_T("override"), &Override); + } + ~Environment() override = default; + Environment& operator=(const Environment& RHS) + { + Key = RHS.Key; + Value = RHS.Value; + Override = RHS.Override; + + return (*this); + } + Environment& operator=(Environment&& move) noexcept + { + if (this != &move) { + Key = std::move(move.Key); + Value = std::move(move.Value); + Override = std::move(move.Override); + } + + return (*this); + } + static std::vector List(const Core::JSON::ArrayType& environments) + { + std::vector environmentList; + + if (environments.IsSet() == true) { + Core::JSON::ArrayType::ConstIterator index(environments.Elements()); + while (index.Next() == true) { + if ((index.Current().Key.IsSet() == true) && (index.Current().Value.IsSet() == true)) { + RPC::Object::Environment env; + env.key = index.Current().Key.Value(); + env.value = index.Current().Value.Value(); + env.overriding = index.Current().Override.Value(); + environmentList.push_back(env); + } else { + SYSLOG(Logging::Startup, (_T("Failure in Substituting Value of Key:Value:[%s]:[%s]\n"), index.Current().Key.Value().c_str(), index.Current().Value.Value().c_str())); + } + } + } + return environmentList; + } + static RPC::Object::Environment Info(const string& env, RPC::Object::Environment::Scope overriding) + { + RPC::Object::Environment info; + size_t start = env.find_first_of(RPC::Object::EnvironmentSeparator); + if ((start != string::npos) && (start < env.length())) { + string key = env.substr(0, start); + string value = env.substr(start + 1); + + if ((key.empty() != true) && (value.empty() != true) && (value.length() > 2) && + ((value.at(0) == '\"') && (value.at(value.length() - 1) == '\"'))) { + info.key = key; + info.value = value.substr(1, value.length() - 2); + info.overriding = overriding; + } else { + SYSLOG(Logging::Startup, (_T("Environment key:value fromat is invalid :[%s]:[%s]\n"), key.c_str(), value.c_str())); + } + } else { + SYSLOG(Logging::Startup, (_T("Invalid Enviroment value :[%s]\n"), env.c_str())); + } + return info; + } + + public: + Core::JSON::String Key; + Core::JSON::String Value; + Core::JSON::EnumType Override; + }; + using EnvironmentList = Core::JSON::ArrayType; + class EXTERNAL RootConfig : public Core::JSON::Container { private: class RootObject : public Core::JSON::Container { @@ -73,6 +173,7 @@ namespace Plugin { , Mode(ModeType::LOCAL) , RemoteAddress() , Configuration(false) + , Environments() { Add(_T("locator"), &Locator); Add(_T("user"), &User); @@ -83,6 +184,7 @@ namespace Plugin { Add(_T("mode"), &Mode); Add(_T("remoteaddress"), &RemoteAddress); Add(_T("configuration"), &Configuration); + Add(_T("environments"), &Environments); } RootConfig(const PluginHost::IShell* info) : Core::JSON::Container() @@ -95,6 +197,7 @@ namespace Plugin { , Mode(ModeType::LOCAL) , RemoteAddress() , Configuration(false) + , Environments() { Add(_T("locator"), &Locator); Add(_T("user"), &User); @@ -105,6 +208,7 @@ namespace Plugin { Add(_T("mode"), &Mode); Add(_T("remoteaddress"), &RemoteAddress); Add(_T("configuration"), &Configuration); + Add(_T("environments"), &Environments); RootObject config; Core::OptionalType error; @@ -139,6 +243,7 @@ namespace Plugin { , Mode(copy.Mode) , RemoteAddress(copy.RemoteAddress) , Configuration(copy.Configuration) + , Environments(copy.Environments) { Add(_T("locator"), &Locator); Add(_T("user"), &User); @@ -149,6 +254,7 @@ namespace Plugin { Add(_T("mode"), &Mode); Add(_T("remoteaddress"), &RemoteAddress); Add(_T("configuration"), &Configuration); + Add(_T("environments"), &Environments); } RootConfig(RootConfig&& move) noexcept : Core::JSON::Container() @@ -161,6 +267,7 @@ namespace Plugin { , Mode(std::move(move.Mode)) , RemoteAddress(std::move(move.RemoteAddress)) , Configuration(std::move(move.Configuration)) + , Environments(std::move(move.Environments)) { Add(_T("locator"), &Locator); Add(_T("user"), &User); @@ -171,6 +278,7 @@ namespace Plugin { Add(_T("mode"), &Mode); Add(_T("remoteaddress"), &RemoteAddress); Add(_T("configuration"), &Configuration); + Add(_T("environments"), &Environments); } ~RootConfig() override = default; @@ -186,6 +294,7 @@ namespace Plugin { Mode = RHS.Mode; RemoteAddress = RHS.RemoteAddress; Configuration = RHS.Configuration; + Environments = RHS.Environments; return (*this); } @@ -202,6 +311,7 @@ namespace Plugin { Mode = std::move(move.Mode); RemoteAddress = std::move(move.RemoteAddress); Configuration = std::move(move.Configuration); + Environments = std::move(move.Environments); } return (*this); @@ -233,6 +343,7 @@ namespace Plugin { Core::JSON::EnumType Mode; Core::JSON::String RemoteAddress; Core::JSON::String Configuration; + EnvironmentList Environments; }; public: diff --git a/Source/plugins/Shell.cpp b/Source/plugins/Shell.cpp index 9d3c8024f..e8d052665 100644 --- a/Source/plugins/Shell.cpp +++ b/Source/plugins/Shell.cpp @@ -50,6 +50,7 @@ namespace PluginHost if (file.Exists()) { Core::Library resource = Core::ServiceAdministrator::Instance().LoadLibrary(element.c_str()); + if (resource.IsLoaded()) result = Core::ServiceAdministrator::Instance().Instantiate( resource, @@ -80,7 +81,8 @@ namespace PluginHost rootConfig.HostType(), SystemRootPath(), rootConfig.RemoteAddress.Value(), - rootConfig.Configuration.Value()); + rootConfig.Configuration.Value(), + Plugin::Config::Environment::List(rootConfig.Environments)); result = handler->Instantiate(definition, waitTime, pid); }