Passenger: PoolOptions.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List

# PoolOptions.h

    00001 /*
    00002  *  Phusion Passenger - http://www.modrails.com/
    00003  *  Copyright (c) 2010 Phusion
    00004  *
    00005  *  "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
    00006  *
    00007  *  Permission is hereby granted, free of charge, to any person obtaining a copy
    00008  *  of this software and associated documentation files (the "Software"), to deal
    00009  *  in the Software without restriction, including without limitation the rights
    00010  *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    00011  *  copies of the Software, and to permit persons to whom the Software is
    00012  *  furnished to do so, subject to the following conditions:
    00013  *
    00014  *  The above copyright notice and this permission notice shall be included in
    00015  *  all copies or substantial portions of the Software.
    00016  *
    00017  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    00018  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    00019  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    00020  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    00021  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    00022  *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    00023  *  THE SOFTWARE.
    00024  */
    00025 #ifndef _PASSENGER_SPAWN_OPTIONS_H_
    00026 #define _PASSENGER_SPAWN_OPTIONS_H_
    00027
    00028 #include <string>
    00029 #include <vector>
    00030 #include "Account.h"
    00031 #include "Logging.h"
    00032 #include "Constants.h"
    00033 #include "StringListCreator.h"
    00034
    00035 namespace Passenger {
    00036
    00037 using namespace std;
    00038
    00039 /**
    00040  * This struct encapsulates information for ApplicationPool::get() and for
    00041  * SpawnManager::spawn(), such as which application is to be spawned.
    00042  *
    00043  * <h2>Privilege lowering support</h2>
    00044  *
    00045  * If <em>user</em> is given and isn't the empty string, then the application process
    00046  * will run as the given username. Otherwise, the owner of the application's startup
    00047  * file (e.g. config/environment.rb or config.ru) will be used.
    00048  *
    00049  * If <em>group</em> is given and isn't the empty string, then the application process
    00050  * will run as the given group name. If it's set to the special value
    00051  * "!STARTUP_FILE!", then the startup file's group will be used. Otherwise,
    00052  * the primary group of the user that the application process will run as,
    00053  * will be used as group.
    00054  *
    00055  * If the user or group that the application process attempts to switch to
    00056  * doesn't exist, then <em>default_user</em> and <em>default_group</em>, respectively,
    00057  * will be used.
    00058  *
    00059  * Phusion Passenger will attempt to avoid running the application process as
    00060  * root: if <em>user</em> or <em>group</em> is set to the root user or the root group,
    00061  * or if the startup file is owned by root, then <em>default_user</em> and
    00062  * <em>default_group</em> will be used instead.
    00063  *
    00064  * All this only happen if Phusion Passenger has root privileges. If not, then
    00065  * these options have no effect.
    00066  */
    00067 struct PoolOptions {
    00068         /**
    00069          * The root directory of the application to spawn. In case of a Ruby on Rails
    00070          * application, this is the folder that contains 'app/', 'public/', 'config/',
    00071          * etc. This must be a valid directory, but the path does not have to be absolute.
    00072          */
    00073         string appRoot;
    00074
    00075         /**
    00076          * A name used by ApplicationPool to uniquely identify an application.
    00077          * If one tries to get() from the application pool with name "A", then get()
    00078          * again with name "B", then the latter will spawn a new application process,
    00079          * even if both get() requests have the same app root.
    00080          *
    00081          * If left empty (the default), then the app root is used as the app group
    00082          * name.
    00083          */
    00084         string appGroupName;
    00085
    00086         /** The application type. Either "rails" (default), "rack" or "wsgi". */
    00087         string appType;
    00088
    00089         /**
    00090          * The RAILS_ENV/RACK_ENV environment that should be used. May not be an
    00091          * empty string. The default is "production".
    00092          */
    00093         string environment;
    00094
    00095         /**
    00096          * Method with which application processes should be spawned. Different methods
    00097          * have different performance and compatibility properties. Available methods are
    00098          * "smart-lv2" (default), "smart" and "conservative". The different spawning methods
    00099          * are explained in the "Spawning methods explained" section of the users guide.
    00100          */
    00101         string spawnMethod;
    00102
    00103         /** See overview. */
    00104         string user;
    00105         /** See class overview. */
    00106         string group;
    00107         /** See class overview. Defaults to "nobody". */
    00108         string defaultUser;
    00109         /** See class overview. Defaults to the defaultUser's primary group. */
    00110         string defaultGroup;
    00111
    00112         /**
    00113          * The idle timeout, in seconds, of framework spawners. See the "Spawning methods
    00114          * explained" section of the users guide for information about framework spawners.
    00115          *
    00116          * A timeout of 0 means that the framework spawner should never idle timeout. A timeout
    00117          * of -1 means that the default timeout value should be used.
    00118          */
    00119         long frameworkSpawnerTimeout;
    00120
    00121         /**
    00122          * The idle timeout, in seconds, of application spawners. See the "Spawning methods
    00123          * explained" section of the users guide for information about application spawners.
    00124          *
    00125          * A timeout of 0 means that the application spawner should never idle timeout. A timeout
    00126          * of -1 means that the default timeout value should be used.
    00127          */
    00128         long appSpawnerTimeout;
    00129
    00130         /**
    00131          * Environment variables which should be passed to the spawned application
    00132          * process.
    00133          *
    00134          * If a new application process is started, then the getItems() method
    00135          * on this object will be called, which is to return environment
    00136          * variables that should be passed to the newly spawned backend process.
    00137          * Odd indices in the resulting array contain keys, even indices contain
    00138          * the value for the key in the previous index.
    00139          *
    00140          * May be set to NULL.
    00141          *
    00142          * @invariant environmentVariables.size() is an even number.
    00143          */
    00144         StringListCreatorPtr environmentVariables;
    00145
    00146         /**
    00147          * The base URI on which the application runs. If the application is
    00148          * running on the root URI, then this value must be "/".
    00149          *
    00150          * @invariant baseURI != ""
    00151          */
    00152         string baseURI;
    00153
    00154         /**
    00155          * The maximum number of requests that the spawned application may process
    00156          * before exiting. A value of 0 means unlimited.
    00157          */
    00158         unsigned long maxRequests;
    00159
    00160         /**
    00161          * The minimum number of processes for the current group that the application
    00162          * pool's cleaner thread should keep around.
    00163          */
    00164         unsigned long minProcesses;
    00165
    00166         /**
    00167          * Whether to use a global queue instead of a per-backend process
    00168          * queue. This option is only used by ApplicationPool::get().
    00169          *
    00170          * If enabled, when all backend processes are active, get() will
    00171          * wait until there's at least one backend process that's idle, instead
    00172          * of queuing the request into a random process's private queue.
    00173          * This is especially useful if a website has one or more long-running
    00174          * requests.
    00175          */
    00176         bool useGlobalQueue;
    00177
    00178         /**
    00179          * Whether to show the Phusion Passenger version number in the
    00180          * X-Powered-By header.
    00181          */
    00182         bool showVersionInHeader;
    00183
    00184         /**
    00185          * A throttling rate for file stats. When set to a non-zero value N,
    00186          * restart.txt and other files which are usually stat()ted on every
    00187          * ApplicationPool::get() call will be stat()ed at most every N seconds.
    00188          */
    00189         unsigned long statThrottleRate;
    00190
    00191         /**
    00192          * The directory which contains restart.txt and always_restart.txt.
    00193          * An empty string means that the default directory should be used.
    00194          */
    00195         string restartDir;
    00196
    00197         /**
    00198          * Any rights that the spawned application process may have. The SpawnManager
    00199          * will create a new account for each spawned app, and that account will be
    00200          * assigned these rights.
    00201          */
    00202         Account::Rights rights;
    00203
    00204         /** Whether debugger support should be enabled. */
    00205         bool debugger;
    00206
    00207         /** In case an app process needs to be spawned, whether analytics logging
    00208          * should be enabled.
    00209          */
    00210         bool analytics;
    00211
    00212         /**
    00213          * An analytics log object to log things to. May be the null pointer,
    00214          * in which case analytics logging is disabled for this request.
    00215          */
    00216         AnalyticsLogPtr log;
    00217
    00218         /**
    00219          * Whether the session returned by ApplicationPool::Interface::get()
    00220          * should be automatically initiated. Defaults to true.
    00221          */
    00222         bool initiateSession;
    00223
    00224         /**
    00225          * Whether application processes should print exceptions that occurred during
    00226          * application initialization. Defaults to true.
    00227          */
    00228         bool printExceptions;
    00229
    00230         /*********************************/
    00231
    00232         /**
    00233          * Creates a new PoolOptions object with the default values filled in.
    00234          * One must still set appRoot manually, after having used this constructor.
    00235          */
    00236         PoolOptions() {
    00237                 appType                 = "rails";
    00238                 environment             = "production";
    00239                 spawnMethod             = "smart-lv2";
    00240                 frameworkSpawnerTimeout = -1;
    00241                 appSpawnerTimeout       = -1;
    00242                 baseURI                 = "/";
    00243                 maxRequests             = 0;
    00244                 minProcesses            = 0;
    00245                 useGlobalQueue          = false;
    00246                 showVersionInHeader     = true;
    00247                 statThrottleRate        = 0;
    00248                 rights                  = DEFAULT_BACKEND_ACCOUNT_RIGHTS;
    00249                 debugger                = false;
    00250                 analytics               = false;
    00251                 initiateSession         = true;
    00252                 printExceptions         = true;
    00253
    00254                 /*********************************/
    00255         }
    00256
    00257         /**
    00258          * Creates a new PoolOptions object with the given values.
    00259          */
    00260         PoolOptions(const string &appRoot,
    00261                 string appGroupName          = "",
    00262                 const string &appType        = "rails",
    00263                 const string &environment    = "production",
    00264                 const string &spawnMethod    = "smart-lv2",
    00265                 const string &user           = "",
    00266                 const string &group          = "",
    00267                 const string &defaultUser    = "",
    00268                 const string &defaultGroup   = "",
    00269                 long frameworkSpawnerTimeout = -1,
    00270                 long appSpawnerTimeout       = -1,
    00271                 const string &baseURI        = "/",
    00272                 unsigned long maxRequests    = 0,
    00273                 unsigned long minProcesses   = 0,
    00274                 bool useGlobalQueue          = false,
    00275                 bool showVersionInHeader     = true,
    00276                 unsigned long statThrottleRate = 0,
    00277                 const string &restartDir     = "",
    00278                 Account::Rights rights       = DEFAULT_BACKEND_ACCOUNT_RIGHTS,
    00279                 bool debugger                = false,
    00280                 bool analytics               = false,
    00281                 const AnalyticsLogPtr &log   = AnalyticsLogPtr()
    00282         ) {
    00283                 this->appRoot                 = appRoot;
    00284                 this->appGroupName            = appGroupName;
    00285                 this->appType                 = appType;
    00286                 this->environment             = environment;
    00287                 this->spawnMethod             = spawnMethod;
    00288                 this->user                    = user;
    00289                 this->group                   = group;
    00290                 this->defaultUser             = defaultUser;
    00291                 this->defaultGroup            = defaultGroup;
    00292                 this->frameworkSpawnerTimeout = frameworkSpawnerTimeout;
    00293                 this->appSpawnerTimeout       = appSpawnerTimeout;
    00294                 this->baseURI                 = baseURI;
    00295                 this->maxRequests             = maxRequests;
    00296                 this->minProcesses            = minProcesses;
    00297                 this->useGlobalQueue          = useGlobalQueue;
    00298                 this->showVersionInHeader     = showVersionInHeader;
    00299                 this->statThrottleRate        = statThrottleRate;
    00300                 this->restartDir              = restartDir;
    00301                 this->rights                  = rights;
    00302                 this->debugger                = debugger;
    00303                 this->analytics               = analytics;
    00304                 this->log                     = log;
    00305                 this->initiateSession         = true;
    00306                 this->printExceptions         = true;
    00307
    00308                 /*********************************/
    00309         }
    00310
    00311         /**
    00312          * Creates a new PoolOptions object from the given string vector.
    00313          * This vector contains information that's written to by toVector().
    00314          *
    00315          * For example:
    00316          * @code
    00317          *   PoolOptions options(...);
    00318          *   vector<string> vec;
    00319          *
    00320          *   vec.push_back("my");
    00321          *   vec.push_back("data");
    00322          *   options.toVector(vec);  // PoolOptions information will start at index 2.
    00323          *
    00324          *   PoolOptions copy(vec, 2);
    00325          * @endcode
    00326          *
    00327          * @param vec The vector containing spawn options information.
    00328          * @param startIndex The index in vec at which the information starts.
    00329          * @param analyticsLogger If given, and the vector contains logging information,
    00330          *                        then the 'log' member will be constructed using this logger.
    00331          */
    00332         PoolOptions(const vector<string> &vec, unsigned int startIndex = 0,
    00333                     AnalyticsLoggerPtr analyticsLogger = AnalyticsLoggerPtr()
    00334         ) {
    00335                 int offset = 1;
    00336                 bool hasEnvVars;
    00337
    00338                 appRoot          = vec[startIndex + offset];                 offset += 2;
    00339                 appGroupName     = vec[startIndex + offset];                 offset += 2;
    00340                 appType          = vec[startIndex + offset];                 offset += 2;
    00341                 environment      = vec[startIndex + offset];                 offset += 2;
    00342                 spawnMethod      = vec[startIndex + offset];                 offset += 2;
    00343                 user             = vec[startIndex + offset];                 offset += 2;
    00344                 group            = vec[startIndex + offset];                 offset += 2;
    00345                 defaultUser      = vec[startIndex + offset];                 offset += 2;
    00346                 defaultGroup     = vec[startIndex + offset];                 offset += 2;
    00347                 frameworkSpawnerTimeout = atol(vec[startIndex + offset]);    offset += 2;
    00348                 appSpawnerTimeout       = atol(vec[startIndex + offset]);    offset += 2;
    00349                 baseURI          = vec[startIndex + offset];                 offset += 2;
    00350                 maxRequests      = atol(vec[startIndex + offset]);           offset += 2;
    00351                 minProcesses     = atol(vec[startIndex + offset]);           offset += 2;
    00352                 useGlobalQueue   = vec[startIndex + offset] == "true";       offset += 2;
    00353                 showVersionInHeader = vec[startIndex + offset] == "true";    offset += 2;
    00354                 statThrottleRate = atol(vec[startIndex + offset]);           offset += 2;
    00355                 restartDir       = vec[startIndex + offset];                 offset += 2;
    00356                 rights           = (Account::Rights) atol(vec[startIndex + offset]);
    00357                                                                              offset += 2;
    00358                 debugger         = vec[startIndex + offset] == "true";       offset += 2;
    00359                 analytics        = vec[startIndex + offset] == "true";       offset += 2;
    00360                 if (vec[startIndex + offset - 1] == "analytics_log_txn_id") {
    00361                         if (analyticsLogger != NULL) {
    00362                                 string txnId     = vec[startIndex + offset];
    00363                                 string groupName = vec[startIndex + offset + 2];
    00364                                 string category  = vec[startIndex + offset + 4];
    00365                                 string unionStationKey = vec[startIndex + offset + 6];
    00366                                 log = analyticsLogger->continueTransaction(txnId,
    00367                                         groupName, category, unionStationKey);
    00368                         }
    00369                         offset += 8;
    00370                 }
    00371                 initiateSession  = vec[startIndex + offset] == "true";       offset += 2;
    00372                 printExceptions  = vec[startIndex + offset] == "true";       offset += 2;
    00373                 hasEnvVars       = vec[startIndex + offset] == "true";       offset += 2;
    00374                 if (hasEnvVars) {
    00375                         environmentVariables = ptr(new SimpleStringListCreator(vec[startIndex + offset]));
    00376                 }
    00377                 offset += 2;
    00378
    00379                 /*********************************/
    00380         }
    00381
    00382         /**
    00383          * Append the information in this PoolOptions object to the given
    00384          * string vector. The resulting array could, for example, be used
    00385          * as a message to be sent to the spawn server.
    00386          *
    00387          * @param vec The vector to store the information in.
    00388          * @param storeEnvVars Whether to store environment variable information into vec as well.
    00389          * @throws Anything thrown by environmentVariables->getItems().
    00390          */
    00391         void toVector(vector<string> &vec, bool storeEnvVars = true) const {
    00392                 if (vec.capacity() < vec.size() + 40) {
    00393                         vec.reserve(vec.size() + 40);
    00394                 }
    00395                 appendKeyValue (vec, "app_root",           appRoot);
    00396                 appendKeyValue (vec, "app_group_name",     getAppGroupName());
    00397                 appendKeyValue (vec, "app_type",           appType);
    00398                 appendKeyValue (vec, "environment",        environment);
    00399                 appendKeyValue (vec, "spawn_method",       spawnMethod);
    00400                 appendKeyValue (vec, "user",               user);
    00401                 appendKeyValue (vec, "group",              group);
    00402                 appendKeyValue (vec, "default_user",       defaultUser);
    00403                 appendKeyValue (vec, "default_group",      defaultGroup);
    00404                 appendKeyValue2(vec, "framework_spawner_timeout", frameworkSpawnerTimeout);
    00405                 appendKeyValue2(vec, "app_spawner_timeout",       appSpawnerTimeout);
    00406                 appendKeyValue (vec, "base_uri",           baseURI);
    00407                 appendKeyValue3(vec, "max_requests",       maxRequests);
    00408                 appendKeyValue3(vec, "min_processes",      minProcesses);
    00409                 appendKeyValue4(vec, "use_global_queue",   useGlobalQueue);
    00410                 appendKeyValue4(vec, "show_version_in_header", showVersionInHeader);
    00411                 appendKeyValue3(vec, "stat_throttle_rate", statThrottleRate);
    00412                 appendKeyValue (vec, "restart_dir",        restartDir);
    00413                 appendKeyValue3(vec, "rights",             rights);
    00414                 appendKeyValue4(vec, "debugger",           debugger);
    00415                 appendKeyValue4(vec, "analytics",          analytics);
    00416                 if (log) {
    00417                         appendKeyValue(vec, "analytics_log_txn_id", log->getTxnId());
    00418                         appendKeyValue(vec, "analytics_log_group_name", log->getGroupName());
    00419                         appendKeyValue(vec, "analytics_log_category", log->getCategory());
    00420                         appendKeyValue(vec, "union_station_key", log->getUnionStationKey());
    00421                 }
    00422                 appendKeyValue4(vec, "initiate_session",   initiateSession);
    00423                 appendKeyValue4(vec, "print_exceptions",   printExceptions);
    00424                 if (storeEnvVars) {
    00425                         appendKeyValue(vec, "has_environment_variables", "true");
    00426                         appendKeyValue(vec, "environment_variables", serializeEnvironmentVariables());
    00427                 } else {
    00428                         appendKeyValue(vec, "has_environment_variables", "false");
    00429                         appendKeyValue(vec, "environment_variables", "");
    00430                 }
    00431
    00432                 /*********************************/
    00433         }
    00434
    00435         PoolOptions own() const {
    00436                 PoolOptions copy = *this;
    00437                 if (copy.environmentVariables != NULL) {
    00438                         copy.environmentVariables->getItems(); // Prefetch items now while we still can.
    00439                 }
    00440                 return copy;
    00441         }
    00442
    00443         /**
    00444          * Returns the app group name. If there is no explicitly set app group name
    00445          * then the app root is considered to be the app group name.
    00446          */
    00447         string getAppGroupName() const {
    00448                 if (appGroupName.empty()) {
    00449                         return appRoot;
    00450                 } else {
    00451                         return appGroupName;
    00452                 }
    00453         }
    00454
    00455         /**
    00456          * Serializes the items in environmentVariables into a string, which
    00457          * can be used to create a SimpleStringListCreator object.
    00458          *
    00459          * @throws Anything thrown by environmentVariables->getItems().
    00460          */
    00461         string serializeEnvironmentVariables() const {
    00462                 vector<string>::const_iterator it, end;
    00463                 string result;
    00464
    00465                 if (environmentVariables) {
    00466                         result.reserve(1024);
    00467
    00468                         StringListPtr items = environmentVariables->getItems();
    00469                         end = items->end();
    00470
    00471                         for (it = items->begin(); it != end; it++) {
    00472                                 result.append(*it);
    00473                                 result.append(1, '\0');
    00474                                 it++;
    00475                                 result.append(*it);
    00476                                 result.append(1, '\0');
    00477                         }
    00478                 }
    00479                 return Base64::encode(result);
    00480         }
    00481
    00482 private:
    00483         static inline void
    00484         appendKeyValue(vector<string> &vec, const char *key, const string &value) {
    00485                 vec.push_back(key);
    00486                 vec.push_back(const_cast<string &>(value));
    00487         }
    00488
    00489         static inline void
    00490         appendKeyValue(vector<string> &vec, const char *key, const char *value) {
    00491                 vec.push_back(key);
    00492                 vec.push_back(value);
    00493         }
    00494
    00495         static inline void
    00496         appendKeyValue2(vector<string> &vec, const char *key, long value) {
    00497                 vec.push_back(key);
    00498                 vec.push_back(toString(value));
    00499         }
    00500
    00501         static inline void
    00502         appendKeyValue3(vector<string> &vec, const char *key, unsigned long value) {
    00503                 vec.push_back(key);
    00504                 vec.push_back(toString(value));
    00505         }
    00506
    00507         static inline void
    00508         appendKeyValue4(vector<string> &vec, const char *key, bool value) {
    00509                 vec.push_back(key);
    00510                 vec.push_back(value ? "true" : "false");
    00511         }
    00512 };
    00513
    00514 } // namespace Passenger
    00515
    00516 #endif /* _PASSENGER_SPAWN_OPTIONS_H_ */
    00517