00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef _PASSENGER_SPAWN_MANAGER_H_
00021 #define _PASSENGER_SPAWN_MANAGER_H_
00022
00023 #include <string>
00024 #include <list>
00025 #include <boost/shared_ptr.hpp>
00026 #include <boost/thread.hpp>
00027
00028 #include <sys/types.h>
00029 #include <sys/wait.h>
00030 #include <sys/stat.h>
00031 #include <arpa/inet.h>
00032 #include <cstdio>
00033 #include <cstdarg>
00034 #include <unistd.h>
00035 #include <errno.h>
00036 #include <pwd.h>
00037 #include <signal.h>
00038
00039 #include "Application.h"
00040 #include "MessageChannel.h"
00041 #include "Exceptions.h"
00042 #include "Logging.h"
00043 #include "System.h"
00044
00045 namespace Passenger {
00046
00047 using namespace std;
00048 using namespace boost;
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 class SpawnManager {
00084 private:
00085 static const int SPAWN_SERVER_INPUT_FD = 3;
00086
00087 string spawnServerCommand;
00088 string logFile;
00089 string rubyCommand;
00090 string user;
00091
00092 mutex lock;
00093
00094 MessageChannel channel;
00095 pid_t pid;
00096 bool serverNeedsRestart;
00097
00098
00099
00100
00101
00102
00103
00104
00105 void restartServer() {
00106 if (pid != 0) {
00107 channel.close();
00108
00109
00110
00111
00112 time_t begin = InterruptableCalls::time(NULL);
00113 bool done = false;
00114 while (!done && InterruptableCalls::time(NULL) - begin < 5) {
00115 if (InterruptableCalls::waitpid(pid, NULL, WNOHANG) > 0) {
00116 done = true;
00117 } else {
00118 InterruptableCalls::usleep(100000);
00119 }
00120 }
00121 if (!done) {
00122 P_TRACE(2, "Spawn server did not exit in time, killing it...");
00123 InterruptableCalls::kill(pid, SIGTERM);
00124 begin = InterruptableCalls::time(NULL);
00125 while (InterruptableCalls::time(NULL) - begin < 5) {
00126 if (InterruptableCalls::waitpid(pid, NULL, WNOHANG) > 0) {
00127 break;
00128 } else {
00129 InterruptableCalls::usleep(100000);
00130 }
00131 }
00132 P_TRACE(2, "Spawn server has exited.");
00133 }
00134 pid = 0;
00135 }
00136
00137 int fds[2];
00138 FILE *logFileHandle = NULL;
00139
00140 serverNeedsRestart = true;
00141 if (InterruptableCalls::socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
00142 throw SystemException("Cannot create a Unix socket", errno);
00143 }
00144 if (!logFile.empty()) {
00145 logFileHandle = InterruptableCalls::fopen(logFile.c_str(), "a");
00146 if (logFileHandle == NULL) {
00147 string message("Cannot open log file '");
00148 message.append(logFile);
00149 message.append("' for writing.");
00150 throw IOException(message);
00151 }
00152 }
00153
00154 pid = InterruptableCalls::fork();
00155 if (pid == 0) {
00156 if (!logFile.empty()) {
00157 dup2(fileno(logFileHandle), STDERR_FILENO);
00158 fclose(logFileHandle);
00159 }
00160 dup2(STDERR_FILENO, STDOUT_FILENO);
00161 dup2(fds[1], SPAWN_SERVER_INPUT_FD);
00162
00163
00164 for (long i = sysconf(_SC_OPEN_MAX) - 1; i > SPAWN_SERVER_INPUT_FD; i--) {
00165 close(i);
00166 }
00167
00168 if (!user.empty()) {
00169 struct passwd *entry = getpwnam(user.c_str());
00170 if (entry != NULL) {
00171 if (setgid(entry->pw_gid) != 0) {
00172 int e = errno;
00173 fprintf(stderr, "*** Passenger: cannot run spawn "
00174 "manager as group %d: %s (%d)\n",
00175 entry->pw_gid,
00176 strerror(e),
00177 e);
00178 }
00179 if (setuid(entry->pw_uid) != 0) {
00180 int e = errno;
00181 fprintf(stderr, "*** Passenger: cannot run spawn "
00182 "manager as user %s (%d): %s (%d)\n",
00183 user.c_str(), entry->pw_uid,
00184 strerror(e),
00185 e);
00186 }
00187 } else {
00188 fprintf(stderr, "*** Passenger: cannot run spawn manager "
00189 "as nonexistant user '%s'.\n",
00190 user.c_str());
00191 }
00192 fflush(stderr);
00193 }
00194
00195 execlp(rubyCommand.c_str(),
00196 rubyCommand.c_str(),
00197 spawnServerCommand.c_str(),
00198
00199
00200
00201
00202
00203
00204 " ",
00205 NULL);
00206 int e = errno;
00207 fprintf(stderr, "*** Passenger ERROR: Could not start the spawn server: %s: %s (%d)\n",
00208 rubyCommand.c_str(), strerror(e), e);
00209 fflush(stderr);
00210 _exit(1);
00211 } else if (pid == -1) {
00212 int e = errno;
00213 InterruptableCalls::close(fds[0]);
00214 InterruptableCalls::close(fds[1]);
00215 if (logFileHandle != NULL) {
00216 InterruptableCalls::fclose(logFileHandle);
00217 }
00218 pid = 0;
00219 throw SystemException("Unable to fork a process", e);
00220 } else {
00221 InterruptableCalls::close(fds[1]);
00222 if (!logFile.empty()) {
00223 InterruptableCalls::fclose(logFileHandle);
00224 }
00225 channel = MessageChannel(fds[0]);
00226 serverNeedsRestart = false;
00227
00228 #ifdef TESTING_SPAWN_MANAGER
00229 if (nextRestartShouldFail) {
00230 InterruptableCalls::kill(pid, SIGTERM);
00231 InterruptableCalls::usleep(500000);
00232 }
00233 #endif
00234 }
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 ApplicationPtr sendSpawnCommand(
00250 const string &appRoot,
00251 bool lowerPrivilege,
00252 const string &lowestUser,
00253 const string &environment,
00254 const string &spawnMethod,
00255 const string &appType
00256 ) {
00257 vector<string> args;
00258 int ownerPipe;
00259
00260 try {
00261 channel.write("spawn_application",
00262 appRoot.c_str(),
00263 (lowerPrivilege) ? "true" : "false",
00264 lowestUser.c_str(),
00265 environment.c_str(),
00266 spawnMethod.c_str(),
00267 appType.c_str(),
00268 NULL);
00269 } catch (const SystemException &e) {
00270 throw SpawnException(string("Could not write 'spawn_application' "
00271 "command to the spawn server: ") + e.sys());
00272 }
00273
00274 try {
00275
00276 if (!channel.read(args)) {
00277 throw SpawnException("The spawn server has exited unexpectedly.");
00278 }
00279 if (args.size() != 1) {
00280 throw SpawnException("The spawn server sent an invalid message.");
00281 }
00282 if (args[0] == "error_page") {
00283 string errorPage;
00284
00285 if (!channel.readScalar(errorPage)) {
00286 throw SpawnException("The spawn server has exited unexpectedly.");
00287 }
00288 throw SpawnException("An error occured while spawning the application.",
00289 errorPage);
00290 } else if (args[0] != "ok") {
00291 throw SpawnException("The spawn server sent an invalid message.");
00292 }
00293
00294
00295 if (!channel.read(args)) {
00296 throw SpawnException("The spawn server has exited unexpectedly.");
00297 }
00298 } catch (const SystemException &e) {
00299 throw SpawnException(string("Could not read from the spawn server: ") + e.sys());
00300 }
00301
00302 try {
00303 ownerPipe = channel.readFileDescriptor();
00304 } catch (const SystemException &e) {
00305 throw SpawnException(string("Could not receive the spawned "
00306 "application's owner pipe from the spawn server: ") +
00307 e.sys());
00308 } catch (const IOException &e) {
00309 throw SpawnException(string("Could not receive the spawned "
00310 "application's owner pipe from the spawn server: ") +
00311 e.what());
00312 }
00313
00314 if (args.size() != 3) {
00315 InterruptableCalls::close(ownerPipe);
00316 throw SpawnException("The spawn server sent an invalid message.");
00317 }
00318
00319 pid_t pid = atoi(args[0]);
00320 bool usingAbstractNamespace = args[2] == "true";
00321
00322 if (!usingAbstractNamespace) {
00323 int ret;
00324 do {
00325 ret = chmod(args[1].c_str(), S_IRUSR | S_IWUSR);
00326 } while (ret == -1 && errno == EINTR);
00327 do {
00328 ret = chown(args[1].c_str(), getuid(), getgid());
00329 } while (ret == -1 && errno == EINTR);
00330 }
00331 return ApplicationPtr(new Application(appRoot, pid, args[1],
00332 usingAbstractNamespace, ownerPipe));
00333 }
00334
00335
00336
00337
00338 ApplicationPtr
00339 handleSpawnException(const SpawnException &e, const string &appRoot,
00340 bool lowerPrivilege, const string &lowestUser,
00341 const string &environment, const string &spawnMethod,
00342 const string &appType) {
00343 bool restarted;
00344 try {
00345 P_DEBUG("Spawn server died. Attempting to restart it...");
00346 this_thread::disable_syscall_interruption dsi;
00347 restartServer();
00348 P_DEBUG("Restart seems to be successful.");
00349 restarted = true;
00350 } catch (const IOException &e) {
00351 P_DEBUG("Restart failed: " << e.what());
00352 restarted = false;
00353 } catch (const SystemException &e) {
00354 P_DEBUG("Restart failed: " << e.what());
00355 restarted = false;
00356 }
00357 if (restarted) {
00358 return sendSpawnCommand(appRoot, lowerPrivilege, lowestUser,
00359 environment, spawnMethod, appType);
00360 } else {
00361 throw SpawnException("The spawn server died unexpectedly, and restarting it failed.");
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370
00371 void sendReloadCommand(const string &appRoot) {
00372 try {
00373 channel.write("reload", appRoot.c_str(), NULL);
00374 } catch (const SystemException &e) {
00375 throw SystemException("Could not write 'reload' command "
00376 "to the spawn server", e.code());
00377 }
00378 }
00379
00380 void handleReloadException(const SystemException &e, const string &appRoot) {
00381 bool restarted;
00382 try {
00383 P_DEBUG("Spawn server died. Attempting to restart it...");
00384 restartServer();
00385 P_DEBUG("Restart seems to be successful.");
00386 restarted = true;
00387 } catch (const IOException &e) {
00388 P_DEBUG("Restart failed: " << e.what());
00389 restarted = false;
00390 } catch (const SystemException &e) {
00391 P_DEBUG("Restart failed: " << e.what());
00392 restarted = false;
00393 }
00394 if (restarted) {
00395 return sendReloadCommand(appRoot);
00396 } else {
00397 throw SpawnException("The spawn server died unexpectedly, and restarting it failed.");
00398 }
00399 }
00400
00401 IOException prependMessageToException(const IOException &e, const string &message) {
00402 return IOException(message + ": " + e.what());
00403 }
00404
00405 SystemException prependMessageToException(const SystemException &e, const string &message) {
00406 return SystemException(message + ": " + e.brief(), e.code());
00407 }
00408
00409 public:
00410 #ifdef TESTING_SPAWN_MANAGER
00411 bool nextRestartShouldFail;
00412 #endif
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 SpawnManager(const string &spawnServerCommand,
00434 const string &logFile = "",
00435 const string &rubyCommand = "ruby",
00436 const string &user = "") {
00437 this->spawnServerCommand = spawnServerCommand;
00438 this->logFile = logFile;
00439 this->rubyCommand = rubyCommand;
00440 this->user = user;
00441 pid = 0;
00442 #ifdef TESTING_SPAWN_MANAGER
00443 nextRestartShouldFail = false;
00444 #endif
00445 this_thread::disable_interruption di;
00446 this_thread::disable_syscall_interruption dsi;
00447 try {
00448 restartServer();
00449 } catch (const IOException &e) {
00450 throw prependMessageToException(e, "Could not start the spawn server");
00451 } catch (const SystemException &e) {
00452 throw prependMessageToException(e, "Could not start the spawn server");
00453 }
00454 }
00455
00456 ~SpawnManager() throw() {
00457 if (pid != 0) {
00458 this_thread::disable_interruption di;
00459 this_thread::disable_syscall_interruption dsi;
00460 P_TRACE(2, "Shutting down spawn manager (PID " << pid << ").");
00461 channel.close();
00462 InterruptableCalls::waitpid(pid, NULL, 0);
00463 P_TRACE(2, "Spawn manager exited.");
00464 }
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 ApplicationPtr spawn(
00510 const string &appRoot,
00511 bool lowerPrivilege = true,
00512 const string &lowestUser = "nobody",
00513 const string &environment = "production",
00514 const string &spawnMethod = "smart",
00515 const string &appType = "rails"
00516 ) {
00517 mutex::scoped_lock l(lock);
00518 try {
00519 return sendSpawnCommand(appRoot, lowerPrivilege, lowestUser,
00520 environment, spawnMethod, appType);
00521 } catch (const SpawnException &e) {
00522 if (e.hasErrorPage()) {
00523 throw;
00524 } else {
00525 return handleSpawnException(e, appRoot, lowerPrivilege,
00526 lowestUser, environment, spawnMethod, appType);
00527 }
00528 }
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 void reload(const string &appRoot) {
00547 this_thread::disable_interruption di;
00548 this_thread::disable_syscall_interruption dsi;
00549 try {
00550 return sendReloadCommand(appRoot);
00551 } catch (const SystemException &e) {
00552 return handleReloadException(e, appRoot);
00553 }
00554 }
00555
00556
00557
00558
00559
00560 pid_t getServerPid() const {
00561 return pid;
00562 }
00563 };
00564
00565
00566 typedef shared_ptr<SpawnManager> SpawnManagerPtr;
00567
00568 }
00569
00570 #endif