관리-도구
편집 파일: Spawner.h
/* * Phusion Passenger - https://www.phusionpassenger.com/ * Copyright (c) 2011-2018 Phusion Holding B.V. * * "Passenger", "Phusion Passenger" and "Union Station" are registered * trademarks of Phusion Holding B.V. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef _PASSENGER_SPAWNING_KIT_SPAWNER_H_ #define _PASSENGER_SPAWNING_KIT_SPAWNER_H_ #include <boost/shared_ptr.hpp> #include <oxt/system_calls.hpp> #include <modp_b64.h> #include <AppLocalConfigFileUtils.h> #include <LoggingKit/Logging.h> #include <SystemTools/SystemTime.h> #include <Core/SpawningKit/Context.h> #include <Core/SpawningKit/Result.h> #include <Core/SpawningKit/UserSwitchingRules.h> namespace Passenger { namespace SpawningKit { using namespace std; using namespace boost; using namespace oxt; class Spawner { private: StringKeyTable<StaticString> decodeEnvironmentVariables(const StaticString &envvarsData) { StringKeyTable<StaticString> result; string::size_type keyStart = 0; while (keyStart < envvarsData.size()) { string::size_type keyEnd = envvarsData.find('\0', keyStart); string::size_type valueStart = keyEnd + 1; if (valueStart >= envvarsData.size()) { break; } string::size_type valueEnd = envvarsData.find('\0', valueStart); if (valueEnd >= envvarsData.size()) { break; } StaticString key = envvarsData.substr(keyStart, keyEnd - keyStart); StaticString value = envvarsData.substr(valueStart, valueEnd - valueStart); result.insert(key, value, true); keyStart = valueEnd + 1; } result.compact(); return result; } protected: Context *context; void setConfigFromAppPoolOptions(Config *config, Json::Value &extraArgs, const AppPoolOptions &options) { TRACE_POINT(); string envvarsData; try { envvarsData = modp::b64_decode(options.environmentVariables.data(), options.environmentVariables.size()); } catch (const std::runtime_error &) { P_WARN("Unable to decode base64-encoded environment variables: " << options.environmentVariables); envvarsData.clear(); } AppLocalConfig appLocalConfig = parseAppLocalConfigFile(options.appRoot); string startCommand; if (appLocalConfig.appSupportsKuriaProtocol) { config->genericApp = false; config->startsUsingWrapper = false; config->startCommand = options.appStartCommand; } else if (options.appType.empty()) { config->genericApp = true; config->startCommand = options.appStartCommand; } else { startCommand = options.getStartCommand(*context->resourceLocator, *context->wrapperRegistry); config->genericApp = false; config->startsUsingWrapper = true; config->startCommand = startCommand; } config->appGroupName = options.getAppGroupName(); config->appRoot = options.appRoot; config->logLevel = options.logLevel; config->wrapperSuppliedByThirdParty = false; config->findFreePort = false; config->preloadBundler = options.preloadBundler; config->loadShellEnvvars = options.loadShellEnvvars; config->startupFile = options.getStartupFile(*context->wrapperRegistry); config->appType = options.appType; config->processTitle = options.getProcessTitle(*context->wrapperRegistry); config->appEnv = options.environment; config->baseURI = options.baseURI; config->environmentVariables = decodeEnvironmentVariables( envvarsData); config->logFile = options.appLogFile; config->apiKey = options.apiKey; config->groupUuid = options.groupUuid; config->lveMinUid = options.lveMinUid; config->fileDescriptorUlimit = options.fileDescriptorUlimit; config->startTimeoutMsec = options.startTimeout; UserSwitchingInfo info = prepareUserSwitching(options, *context->wrapperRegistry); config->user = info.username; config->group = info.groupname; extraArgs["spawn_method"] = options.spawnMethod.toString(); config->bindAddress = options.bindAddress; /******************/ /******************/ config->internStrings(); } static void nonInterruptableKillAndWaitpid(pid_t pid) { boost::this_thread::disable_syscall_interruption dsi; syscalls::kill(pid, SIGKILL); syscalls::waitpid(pid, NULL, 0); } static void possiblyRaiseInternalError(const AppPoolOptions &options) { if (options.raiseInternalError) { throw RuntimeException("An internal error!"); } } public: /** * Timestamp at which this Spawner was created. Microseconds resolution. */ const unsigned long long creationTime; Spawner(Context *_context) : context(_context), creationTime(SystemTime::getUsec()) { } virtual ~Spawner() { } virtual Result spawn(const AppPoolOptions &options) = 0; virtual bool cleanable() const { return false; } virtual void cleanup() { // Do nothing. } virtual unsigned long long lastUsed() const { return 0; } Context *getContext() const { return context; } }; typedef boost::shared_ptr<Spawner> SpawnerPtr; } // namespace SpawningKit } // namespace Passenger #endif /* _PASSENGER_SPAWNING_KIT_SPAWNER_H_ */