- 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          * A throttling rate for file stats. When set to a non-zero value N,
    00180          * restart.txt and other files which are usually stat()ted on every
    00181          * ApplicationPool::get() call will be stat()ed at most every N seconds.
    00182          */
    00183         unsigned long statThrottleRate;
    00184
    00185         /**
    00186          * The directory which contains restart.txt and always_restart.txt.
    00187          * An empty string means that the default directory should be used.
    00188          */
    00189         string restartDir;
    00190
    00191         /**
    00192          * Any rights that the spawned application process may have. The SpawnManager
    00193          * will create a new account for each spawned app, and that account will be
    00194          * assigned these rights.
    00195          */
    00196         Account::Rights rights;
    00197
    00198         /** Whether debugger support should be enabled. */
    00199         bool debugger;
    00200
    00201         /**
    00202          * An analytics log object to log things to. May be the null pointer,
    00203          * in which case analytics logging is disabled.
    00204          */
    00205         AnalyticsLogPtr log;
    00206
    00207         /**
    00208          * Whether the session returned by ApplicationPool::Interface::get()
    00209          * should be automatically initiated. Defaults to true.
    00210          */
    00211         bool initiateSession;
    00212
    00213         /**
    00214          * Whether application processes should print exceptions that occurred during
    00215          * application initialization. Defaults to true.
    00216          */
    00217         bool printExceptions;
    00218
    00219         /*********************************/
    00220
    00221         /**
    00222          * Creates a new PoolOptions object with the default values filled in.
    00223          * One must still set appRoot manually, after having used this constructor.
    00224          */
    00225         PoolOptions() {
    00226                 appType                 = "rails";
    00227                 environment             = "production";
    00228                 spawnMethod             = "smart-lv2";
    00229                 frameworkSpawnerTimeout = -1;
    00230                 appSpawnerTimeout       = -1;
    00231                 baseURI                 = "/";
    00232                 maxRequests             = 0;
    00233                 minProcesses            = 0;
    00234                 useGlobalQueue          = false;
    00235                 statThrottleRate        = 0;
    00236                 rights                  = DEFAULT_BACKEND_ACCOUNT_RIGHTS;
    00237                 debugger                = false;
    00238                 initiateSession         = true;
    00239                 printExceptions         = true;
    00240
    00241                 /*********************************/
    00242         }
    00243
    00244         /**
    00245          * Creates a new PoolOptions object with the given values.
    00246          */
    00247         PoolOptions(const string &appRoot,
    00248                 string appGroupName          = "",
    00249                 const string &appType        = "rails",
    00250                 const string &environment    = "production",
    00251                 const string &spawnMethod    = "smart-lv2",
    00252                 const string &user           = "",
    00253                 const string &group          = "",
    00254                 const string &defaultUser    = "",
    00255                 const string &defaultGroup   = "",
    00256                 long frameworkSpawnerTimeout = -1,
    00257                 long appSpawnerTimeout       = -1,
    00258                 const string &baseURI        = "/",
    00259                 unsigned long maxRequests    = 0,
    00260                 unsigned long minProcesses   = 0,
    00261                 bool useGlobalQueue          = false,
    00262                 unsigned long statThrottleRate = 0,
    00263                 const string &restartDir     = "",
    00264                 Account::Rights rights       = DEFAULT_BACKEND_ACCOUNT_RIGHTS,
    00265                 bool debugger                = false,
    00266                 const AnalyticsLogPtr &log   = AnalyticsLogPtr()
    00267         ) {
    00268                 this->appRoot                 = appRoot;
    00269                 this->appGroupName            = appGroupName;
    00270                 this->appType                 = appType;
    00271                 this->environment             = environment;
    00272                 this->spawnMethod             = spawnMethod;
    00273                 this->user                    = user;
    00274                 this->group                   = group;
    00275                 this->defaultUser             = defaultUser;
    00276                 this->defaultGroup            = defaultGroup;
    00277                 this->frameworkSpawnerTimeout = frameworkSpawnerTimeout;
    00278                 this->appSpawnerTimeout       = appSpawnerTimeout;
    00279                 this->baseURI                 = baseURI;
    00280                 this->maxRequests             = maxRequests;
    00281                 this->minProcesses            = minProcesses;
    00282                 this->useGlobalQueue          = useGlobalQueue;
    00283                 this->statThrottleRate        = statThrottleRate;
    00284                 this->restartDir              = restartDir;
    00285                 this->rights                  = rights;
    00286                 this->debugger                = debugger;
    00287                 this->log                     = log;
    00288                 this->initiateSession         = true;
    00289                 this->printExceptions         = true;
    00290
    00291                 /*********************************/
    00292         }
    00293
    00294         /**
    00295          * Creates a new PoolOptions object from the given string vector.
    00296          * This vector contains information that's written to by toVector().
    00297          *
    00298          * For example:
    00299          * @code
    00300          *   PoolOptions options(...);
    00301          *   vector<string> vec;
    00302          *
    00303          *   vec.push_back("my");
    00304          *   vec.push_back("data");
    00305          *   options.toVector(vec);  // PoolOptions information will start at index 2.
    00306          *
    00307          *   PoolOptions copy(vec, 2);
    00308          * @endcode
    00309          *
    00310          * @param vec The vector containing spawn options information.
    00311          * @param startIndex The index in vec at which the information starts.
    00312          * @param analyticsLogger If given, and the vector contains logging information,
    00313          *                        then the 'log' member will be constructed using this logger.
    00314          */
    00315         PoolOptions(const vector<string> &vec, unsigned int startIndex = 0,
    00316                     AnalyticsLoggerPtr analyticsLogger = AnalyticsLoggerPtr()
    00317         ) {
    00318                 int offset = 1;
    00319                 bool hasEnvVars;
    00320
    00321                 appRoot          = vec[startIndex + offset];                 offset += 2;
    00322                 appGroupName     = vec[startIndex + offset];                 offset += 2;
    00323                 appType          = vec[startIndex + offset];                 offset += 2;
    00324                 environment      = vec[startIndex + offset];                 offset += 2;
    00325                 spawnMethod      = vec[startIndex + offset];                 offset += 2;
    00326                 user             = vec[startIndex + offset];                 offset += 2;
    00327                 group            = vec[startIndex + offset];                 offset += 2;
    00328                 defaultUser      = vec[startIndex + offset];                 offset += 2;
    00329                 defaultGroup     = vec[startIndex + offset];                 offset += 2;
    00330                 frameworkSpawnerTimeout = atol(vec[startIndex + offset]);    offset += 2;
    00331                 appSpawnerTimeout       = atol(vec[startIndex + offset]);    offset += 2;
    00332                 baseURI          = vec[startIndex + offset];                 offset += 2;
    00333                 maxRequests      = atol(vec[startIndex + offset]);           offset += 2;
    00334                 minProcesses     = atol(vec[startIndex + offset]);           offset += 2;
    00335                 useGlobalQueue   = vec[startIndex + offset] == "true";       offset += 2;
    00336                 statThrottleRate = atol(vec[startIndex + offset]);           offset += 2;
    00337                 restartDir       = vec[startIndex + offset];                 offset += 2;
    00338                 rights           = (Account::Rights) atol(vec[startIndex + offset]);
    00339                                                                              offset += 2;
    00340                 debugger         = vec[startIndex + offset] == "true";       offset += 2;
    00341                 if (vec[startIndex + offset - 1] == "analytics_log_group_name") {
    00342                         if (analyticsLogger != NULL) {
    00343                                 string groupName = vec[startIndex + offset];
    00344                                 string txnId = vec[startIndex + offset + 2];
    00345                                 log = analyticsLogger->continueTransaction(groupName, txnId);
    00346                         }
    00347                         offset += 4;
    00348                 }
    00349                 initiateSession  = vec[startIndex + offset] == "true";       offset += 2;
    00350                 printExceptions  = vec[startIndex + offset] == "true";       offset += 2;
    00351                 hasEnvVars       = vec[startIndex + offset] == "true";       offset += 2;
    00352                 if (hasEnvVars) {
    00353                         environmentVariables = ptr(new SimpleStringListCreator(vec[startIndex + offset]));
    00354                 }
    00355                 offset += 2;
    00356
    00357                 /*********************************/
    00358         }
    00359
    00360         /**
    00361          * Append the information in this PoolOptions object to the given
    00362          * string vector. The resulting array could, for example, be used
    00363          * as a message to be sent to the spawn server.
    00364          *
    00365          * @param vec The vector to store the information in.
    00366          * @param storeEnvVars Whether to store environment variable information into vec as well.
    00367          * @throws Anything thrown by environmentVariables->getItems().
    00368          */
    00369         void toVector(vector<string> &vec, bool storeEnvVars = true) const {
    00370                 if (vec.capacity() < vec.size() + 40) {
    00371                         vec.reserve(vec.size() + 40);
    00372                 }
    00373                 appendKeyValue (vec, "app_root",           appRoot);
    00374                 appendKeyValue (vec, "app_group_name",     getAppGroupName());
    00375                 appendKeyValue (vec, "app_type",           appType);
    00376                 appendKeyValue (vec, "environment",        environment);
    00377                 appendKeyValue (vec, "spawn_method",       spawnMethod);
    00378                 appendKeyValue (vec, "user",               user);
    00379                 appendKeyValue (vec, "group",              group);
    00380                 appendKeyValue (vec, "default_user",       defaultUser);
    00381                 appendKeyValue (vec, "default_group",      defaultGroup);
    00382                 appendKeyValue2(vec, "framework_spawner_timeout", frameworkSpawnerTimeout);
    00383                 appendKeyValue2(vec, "app_spawner_timeout",       appSpawnerTimeout);
    00384                 appendKeyValue (vec, "base_uri",           baseURI);
    00385                 appendKeyValue3(vec, "max_requests",       maxRequests);
    00386                 appendKeyValue3(vec, "min_processes",      minProcesses);
    00387                 appendKeyValue4(vec, "use_global_queue",   useGlobalQueue);
    00388                 appendKeyValue3(vec, "stat_throttle_rate", statThrottleRate);
    00389                 appendKeyValue (vec, "restart_dir",        restartDir);
    00390                 appendKeyValue3(vec, "rights",             rights);
    00391                 appendKeyValue4(vec, "debugger",           debugger);
    00392                 if (log) {
    00393                         appendKeyValue(vec, "analytics_log_group_name", log->getGroupName());
    00394                         appendKeyValue(vec, "analytics_log_id", log->getTxnId());
    00395                 }
    00396                 appendKeyValue4(vec, "initiate_session",   initiateSession);
    00397                 appendKeyValue4(vec, "print_exceptions",   printExceptions);
    00398                 if (storeEnvVars) {
    00399                         appendKeyValue(vec, "has_environment_variables", "true");
    00400                         appendKeyValue(vec, "environment_variables", serializeEnvironmentVariables());
    00401                 } else {
    00402                         appendKeyValue(vec, "has_environment_variables", "false");
    00403                         appendKeyValue(vec, "environment_variables", "");
    00404                 }
    00405
    00406                 /*********************************/
    00407         }
    00408
    00409         /**
    00410          * Returns the app group name. If there is no explicitly set app group name
    00411          * then the app root is considered to be the app group name.
    00412          */
    00413         string getAppGroupName() const {
    00414                 if (appGroupName.empty()) {
    00415                         return appRoot;
    00416                 } else {
    00417                         return appGroupName;
    00418                 }
    00419         }
    00420
    00421         /**
    00422          * Serializes the items in environmentVariables into a string, which
    00423          * can be used to create a SimpleStringListCreator object.
    00424          *
    00425          * @throws Anything thrown by environmentVariables->getItems().
    00426          */
    00427         string serializeEnvironmentVariables() const {
    00428                 vector<string>::const_iterator it, end;
    00429                 string result;
    00430
    00431                 if (environmentVariables) {
    00432                         result.reserve(1024);
    00433
    00434                         StringListPtr items = environmentVariables->getItems();
    00435                         end = items->end();
    00436
    00437                         for (it = items->begin(); it != end; it++) {
    00438                                 result.append(*it);
    00439                                 result.append(1, '\0');
    00440                                 it++;
    00441                                 result.append(*it);
    00442                                 result.append(1, '\0');
    00443                         }
    00444                 }
    00445                 return Base64::encode(result);
    00446         }
    00447
    00448 private:
    00449         static inline void
    00450         appendKeyValue(vector<string> &vec, const char *key, const string &value) {
    00451                 vec.push_back(key);
    00452                 vec.push_back(const_cast<string &>(value));
    00453         }
    00454
    00455         static inline void
    00456         appendKeyValue(vector<string> &vec, const char *key, const char *value) {
    00457                 vec.push_back(key);
    00458                 vec.push_back(value);
    00459         }
    00460
    00461         static inline void
    00462         appendKeyValue2(vector<string> &vec, const char *key, long value) {
    00463                 vec.push_back(key);
    00464                 vec.push_back(toString(value));
    00465         }
    00466
    00467         static inline void
    00468         appendKeyValue3(vector<string> &vec, const char *key, unsigned long value) {
    00469                 vec.push_back(key);
    00470                 vec.push_back(toString(value));
    00471         }
    00472
    00473         static inline void
    00474         appendKeyValue4(vector<string> &vec, const char *key, bool value) {
    00475                 vec.push_back(key);
    00476                 vec.push_back(value ? "true" : "false");
    00477         }
    00478 };
    00479
    00480 } // namespace Passenger
    00481
    00482 #endif /* _PASSENGER_SPAWN_OPTIONS_H_ */
    00483