passenger 5.0.7 → 5.0.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/CHANGELOG +17 -0
- data/bin/passenger-install-apache2-module +37 -5
- data/build/basics.rb +4 -1
- data/build/integration_tests.rb +6 -3
- data/build/packaging.rb +64 -4
- data/dev/ci/run_jenkins.sh +1 -7
- data/dev/ci/run_travis.sh +2 -34
- data/doc/Users guide Apache.html +184 -96
- data/doc/Users guide Apache.idmap.txt +9 -3
- data/doc/Users guide Apache.txt +11 -31
- data/doc/Users guide Nginx.html +192 -53
- data/doc/Users guide Nginx.idmap.txt +9 -3
- data/doc/Users guide Nginx.txt +7 -2
- data/doc/Users guide Standalone.html +113 -55
- data/doc/Users guide Standalone.idmap.txt +5 -1
- data/doc/users_guide_snippets/installation.txt +130 -66
- data/doc/users_guide_snippets/tips.txt +38 -0
- data/ext/apache2/Hooks.cpp +28 -2
- data/ext/common/AgentsStarter.h +6 -0
- data/ext/common/ApplicationPool2/AppTypes.h +1 -1
- data/ext/common/ApplicationPool2/Group.h +25 -3
- data/ext/common/ApplicationPool2/Options.h +1 -1
- data/ext/common/ApplicationPool2/Pool/GarbageCollection.h +6 -3
- data/ext/common/Constants.h +3 -1
- data/ext/common/ServerKit/http_parser.cpp +7 -1
- data/ext/common/agents/HelperAgent/Main.cpp +53 -0
- data/ext/common/agents/HelperAgent/RequestHandler.h +4 -0
- data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +6 -0
- data/ext/nginx/ngx_http_passenger_module.c +2 -2
- data/lib/phusion_passenger.rb +15 -2
- data/lib/phusion_passenger/admin_tools/instance_registry.rb +40 -27
- data/lib/phusion_passenger/config/install_agent_command.rb +4 -0
- data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +6 -0
- data/lib/phusion_passenger/config/installation_utils.rb +8 -2
- data/lib/phusion_passenger/config/nginx_engine_compiler.rb +16 -7
- data/lib/phusion_passenger/config/validate_install_command.rb +87 -11
- data/lib/phusion_passenger/constants.rb +2 -0
- data/lib/phusion_passenger/platform_info/apache.rb +114 -33
- data/lib/phusion_passenger/platform_info/apache_detector.rb +28 -4
- data/lib/phusion_passenger/platform_info/compiler.rb +22 -27
- data/lib/phusion_passenger/standalone/start_command.rb +16 -3
- data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +1 -0
- data/resources/templates/apache2/rpm_installation_recommended.txt.erb +19 -0
- data/resources/templates/standalone/config.erb +3 -2
- metadata +3 -3
- metadata.gz.asc +7 -7
- data/dev/ci/run_rpm_tests.sh +0 -80
@@ -104,6 +104,44 @@ The most likely reason why your application is started as 'nobody' is probably b
|
|
104
104
|
|
105
105
|
Whatever user your application runs as, it must have read access to the <<application_root,application root>>, and read/write access to the application's 'logs' directory.
|
106
106
|
|
107
|
+
[[user_switching_rpm_caveats]]
|
108
|
+
==== Red Hat and CentOS caveats
|
109
|
+
|
110
|
+
NOTE: This information only applies if you installed Passenger through the RPM packages provided by Phusion. If you did not installed Passenger through the RPM packages provided by Phusion, then you can ignore this section.
|
111
|
+
|
112
|
+
If you installed Passenger through Phusion's RPM packages, and you want to disable user switching, then you must also change <<PassengerInstanceRegistryDir,the location of the instance registry directory>>.
|
113
|
+
|
114
|
+
This is because our RPMs configure the default instance registry directory to `/var/run/passenger-instreg`, which is only writable by root. If you disable user switching, then the Passenger processes will run as
|
115
|
+
ifdef::apache[]
|
116
|
+
<<PassengerDefaultUser,PassengerDefaultUser>>,
|
117
|
+
endif::[]
|
118
|
+
ifdef::nginx[]
|
119
|
+
<<PassengerDefaultUser,passenger_default_user>>,
|
120
|
+
endif::[]
|
121
|
+
which (as long as it's not root) won't be able to write to that directory.
|
122
|
+
|
123
|
+
Note that any alternative instance registry directory must have the proper SELinux context, allowing the web server to read and write to it. We recommend that you create a directory `/var/lib/passenger-instreg` and give it the label `var_run_t`:
|
124
|
+
|
125
|
+
------------------------------------------
|
126
|
+
sudo mkdir /var/lib/passenger-instreg
|
127
|
+
sudo chcon -t var_run_t /var/lib/passenger-instreg
|
128
|
+
------------------------------------------
|
129
|
+
|
130
|
+
ifdef::apache[]
|
131
|
+
Then, in your Apache config file:
|
132
|
+
|
133
|
+
------------------------------------------
|
134
|
+
PassengerInstanceRegistryDir /var/lib/passenger-instreg
|
135
|
+
------------------------------------------
|
136
|
+
endif::[]
|
137
|
+
ifdef::nginx[]
|
138
|
+
Then, in your Nginx config file:
|
139
|
+
|
140
|
+
------------------------------------------
|
141
|
+
passenger_instance_registry_dir /var/lib/passenger-instreg;
|
142
|
+
------------------------------------------
|
143
|
+
endif::[]
|
144
|
+
|
107
145
|
[[finding_out_app_user]]
|
108
146
|
==== Finding out what user an application is running as
|
109
147
|
|
data/ext/apache2/Hooks.cpp
CHANGED
@@ -117,6 +117,20 @@ private:
|
|
117
117
|
private:
|
118
118
|
FileSystemException e;
|
119
119
|
|
120
|
+
#ifdef __linux__
|
121
|
+
bool selinuxIsEnforcing() const {
|
122
|
+
FILE *f = fopen("/sys/fs/selinux/enforce", "r");
|
123
|
+
if (f != NULL) {
|
124
|
+
char buf;
|
125
|
+
size_t ret = fread(&buf, 1, 1, f);
|
126
|
+
fclose(f);
|
127
|
+
return ret == 1 && buf == '1';
|
128
|
+
} else {
|
129
|
+
return false;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
#endif
|
133
|
+
|
120
134
|
public:
|
121
135
|
ReportFileSystemError(const FileSystemException &ex): e(ex) { }
|
122
136
|
|
@@ -124,16 +138,28 @@ private:
|
|
124
138
|
r->status = 500;
|
125
139
|
ap_set_content_type(r, "text/html; charset=UTF-8");
|
126
140
|
ap_rputs("<h1>Passenger error #2</h1>\n", r);
|
127
|
-
ap_rputs("An error occurred while trying to access '", r);
|
141
|
+
ap_rputs("<p>An error occurred while trying to access '", r);
|
128
142
|
ap_rputs(ap_escape_html(r->pool, e.filename().c_str()), r);
|
129
143
|
ap_rputs("': ", r);
|
130
144
|
ap_rputs(ap_escape_html(r->pool, e.what()), r);
|
145
|
+
ap_rputs("</p>\n", r);
|
146
|
+
|
131
147
|
if (e.code() == EACCES || e.code() == EPERM) {
|
132
148
|
ap_rputs("<p>", r);
|
133
149
|
ap_rputs("Apache doesn't have read permissions to that file. ", r);
|
134
150
|
ap_rputs("Please fix the relevant file permissions.", r);
|
135
|
-
ap_rputs("</p
|
151
|
+
ap_rputs("</p>\n", r);
|
152
|
+
#ifdef __linux__
|
153
|
+
if (selinuxIsEnforcing()) {
|
154
|
+
ap_rputs("<p>", r);
|
155
|
+
ap_rputs("The permission problems may also be caused by SELinux restrictions. ", r);
|
156
|
+
ap_rputs("Please read " APACHE2_DOC_URL "#apache_selinux_permissions to learn ", r);
|
157
|
+
ap_rputs("how to fix SELinux permission issues. ", r);
|
158
|
+
ap_rputs("</p>", r);
|
159
|
+
}
|
160
|
+
#endif
|
136
161
|
}
|
162
|
+
|
137
163
|
P_ERROR("A filesystem exception occured.\n" <<
|
138
164
|
" Message: " << e.what() << "\n" <<
|
139
165
|
" Backtrace:\n" << e.backtrace());
|
data/ext/common/AgentsStarter.h
CHANGED
@@ -348,6 +348,12 @@ public:
|
|
348
348
|
.setInt ("log_level", getLogLevel());
|
349
349
|
extraParams.addTo(params);
|
350
350
|
|
351
|
+
if (!params.getBool("user_switching", false, true)
|
352
|
+
&& !params.has("user"))
|
353
|
+
{
|
354
|
+
params.set("user", params.get("default_user", false, PASSENGER_DEFAULT_USER));
|
355
|
+
}
|
356
|
+
|
351
357
|
fds = createUnixSocketPair(__FILE__, __LINE__);
|
352
358
|
pid = syscalls::fork();
|
353
359
|
if (pid == 0) {
|
@@ -115,7 +115,7 @@ private:
|
|
115
115
|
TRACE_POINT();
|
116
116
|
throw RuntimeException("Not enough buffer space");
|
117
117
|
}
|
118
|
-
return getFileType(StaticString(buf, pos - buf), cstat, cstatMutex, throttleRate) != FT_NONEXISTANT;
|
118
|
+
return getFileType(StaticString(buf, pos - buf - 1), cstat, cstatMutex, throttleRate) != FT_NONEXISTANT;
|
119
119
|
}
|
120
120
|
|
121
121
|
public:
|
@@ -389,7 +389,7 @@ public:
|
|
389
389
|
RouteResult route(const Options &options) const {
|
390
390
|
if (OXT_LIKELY(enabledCount > 0)) {
|
391
391
|
if (options.stickySessionId == 0) {
|
392
|
-
Process *process =
|
392
|
+
Process *process = findEnabledProcessWithLowestBusyness();
|
393
393
|
if (process->canBeRoutedTo()) {
|
394
394
|
return RouteResult(process);
|
395
395
|
} else {
|
@@ -496,6 +496,29 @@ public:
|
|
496
496
|
return NULL;
|
497
497
|
}
|
498
498
|
|
499
|
+
int lowestBusyness = -1;
|
500
|
+
Process *leastBusyProcess = NULL;
|
501
|
+
ProcessList::const_iterator it;
|
502
|
+
ProcessList::const_iterator end = processes.end();
|
503
|
+
for (it = processes.begin(); it != end; it++) {
|
504
|
+
Process *process = (*it).get();
|
505
|
+
int busyness = process->busyness();
|
506
|
+
if (lowestBusyness == -1 || lowestBusyness > busyness) {
|
507
|
+
lowestBusyness = busyness;
|
508
|
+
leastBusyProcess = process;
|
509
|
+
}
|
510
|
+
}
|
511
|
+
return leastBusyProcess;
|
512
|
+
}
|
513
|
+
|
514
|
+
/**
|
515
|
+
* Cache-optimized version of findProcessWithLowestBusyness() for the common case.
|
516
|
+
*/
|
517
|
+
Process *findEnabledProcessWithLowestBusyness() const {
|
518
|
+
if (enabledProcesses.empty()) {
|
519
|
+
return NULL;
|
520
|
+
}
|
521
|
+
|
499
522
|
int leastBusyProcessIndex = -1;
|
500
523
|
int lowestBusyness = 0;
|
501
524
|
unsigned int i, size = enabledProcessBusynessLevels.size();
|
@@ -1006,8 +1029,7 @@ public:
|
|
1006
1029
|
assert(m_spawning || restarting() || poolAtFullCapacity());
|
1007
1030
|
|
1008
1031
|
if (disablingCount > 0 && !restarting()) {
|
1009
|
-
Process *process = findProcessWithLowestBusyness(
|
1010
|
-
disablingProcesses);
|
1032
|
+
Process *process = findProcessWithLowestBusyness(disablingProcesses);
|
1011
1033
|
assert(process != NULL);
|
1012
1034
|
if (!process->isTotallyBusy()) {
|
1013
1035
|
return newSession(process, newOptions.currentTime);
|
@@ -459,7 +459,7 @@ public:
|
|
459
459
|
environment(DEFAULT_APP_ENV, sizeof(DEFAULT_APP_ENV) - 1),
|
460
460
|
baseURI("/", 1),
|
461
461
|
spawnMethod(DEFAULT_SPAWN_METHOD, sizeof(DEFAULT_SPAWN_METHOD) - 1),
|
462
|
-
defaultUser(
|
462
|
+
defaultUser(PASSENGER_DEFAULT_USER, sizeof(PASSENGER_DEFAULT_USER) - 1),
|
463
463
|
ruby(DEFAULT_RUBY, sizeof(DEFAULT_RUBY) - 1),
|
464
464
|
python(DEFAULT_PYTHON, sizeof(DEFAULT_PYTHON) - 1),
|
465
465
|
nodejs(DEFAULT_NODEJS, sizeof(DEFAULT_NODEJS) - 1),
|
@@ -71,8 +71,7 @@ void checkWhetherProcessCanBeGarbageCollected(GarbageCollectorState &state,
|
|
71
71
|
assert(maxIdleTime > 0);
|
72
72
|
unsigned long long processGcTime = process->lastUsed + maxIdleTime;
|
73
73
|
if (process->sessions == 0
|
74
|
-
&& state.now >= processGcTime
|
75
|
-
&& (unsigned long) group->getProcessCount() > group->options.minProcesses)
|
74
|
+
&& state.now >= processGcTime)
|
76
75
|
{
|
77
76
|
if (output.capacity() == 0) {
|
78
77
|
output.reserve(group->enabledCount);
|
@@ -96,12 +95,16 @@ void garbageCollectProcessesInGroup(GarbageCollectorState &state,
|
|
96
95
|
processesToGc);
|
97
96
|
}
|
98
97
|
|
98
|
+
p_it = processesToGc.begin();
|
99
99
|
p_end = processesToGc.end();
|
100
|
-
|
100
|
+
while (p_it != p_end
|
101
|
+
&& (unsigned long) group->getProcessCount() > group->options.minProcesses)
|
102
|
+
{
|
101
103
|
ProcessPtr process = *p_it;
|
102
104
|
P_DEBUG("Garbage collect idle process: " << process->inspect() <<
|
103
105
|
", group=" << group->name);
|
104
106
|
group->detach(process, state.actions);
|
107
|
+
p_it++;
|
105
108
|
}
|
106
109
|
}
|
107
110
|
|
data/ext/common/Constants.h
CHANGED
@@ -114,7 +114,9 @@
|
|
114
114
|
|
115
115
|
#define NGINX_DOC_URL "https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html"
|
116
116
|
|
117
|
-
#define
|
117
|
+
#define PASSENGER_DEFAULT_USER "nobody"
|
118
|
+
|
119
|
+
#define PASSENGER_VERSION "5.0.8"
|
118
120
|
|
119
121
|
#define POOL_HELPER_THREAD_STACK_SIZE 262144
|
120
122
|
|
@@ -2062,6 +2062,7 @@ http_parse_host_char(enum http_host_state s, const char ch) {
|
|
2062
2062
|
|
2063
2063
|
static int
|
2064
2064
|
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
|
2065
|
+
assert(u->field_set & (1 << UF_HOST));
|
2065
2066
|
enum http_host_state s;
|
2066
2067
|
|
2067
2068
|
const char *p;
|
@@ -2206,7 +2207,12 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
|
2206
2207
|
|
2207
2208
|
/* host must be present if there is a schema */
|
2208
2209
|
/* parsing http:///toto will fail */
|
2209
|
-
if ((u->field_set & (
|
2210
|
+
if ((u->field_set & (1 << UF_SCHEMA)) &&
|
2211
|
+
(u->field_set & (1 << UF_HOST)) == 0) {
|
2212
|
+
return 1;
|
2213
|
+
}
|
2214
|
+
|
2215
|
+
if (u->field_set & (1 << UF_HOST)) {
|
2210
2216
|
if (http_parse_host(buf, u, found_at) != 0) {
|
2211
2217
|
return 1;
|
2212
2218
|
}
|
@@ -31,6 +31,9 @@
|
|
31
31
|
#include <sched.h>
|
32
32
|
#include <pthread.h>
|
33
33
|
#endif
|
34
|
+
#ifdef USE_SELINUX
|
35
|
+
#include <selinux/selinux.h>
|
36
|
+
#endif
|
34
37
|
|
35
38
|
#include <sys/types.h>
|
36
39
|
#include <sys/socket.h>
|
@@ -268,6 +271,47 @@ makeFileWorldReadableAndWritable(const string &path) {
|
|
268
271
|
} while (ret == -1 && errno == EINTR);
|
269
272
|
}
|
270
273
|
|
274
|
+
#ifdef USE_SELINUX
|
275
|
+
// Set next socket context to *:system_r:passenger_instance_httpd_socket_t
|
276
|
+
static void
|
277
|
+
setSelinuxSocketContext() {
|
278
|
+
security_context_t currentCon;
|
279
|
+
string newCon;
|
280
|
+
int e;
|
281
|
+
|
282
|
+
if (getcon(¤tCon) == -1) {
|
283
|
+
e = errno;
|
284
|
+
P_DEBUG("Unable to obtain SELinux context: " <<
|
285
|
+
strerror(e) << " (errno=" << e << ")");
|
286
|
+
return;
|
287
|
+
}
|
288
|
+
|
289
|
+
P_DEBUG("Current SELinux process context: " << currentCon);
|
290
|
+
|
291
|
+
if (strstr(currentCon, ":unconfined_r:unconfined_t:") == NULL) {
|
292
|
+
goto cleanup;
|
293
|
+
}
|
294
|
+
|
295
|
+
newCon = replaceString(currentCon,
|
296
|
+
":unconfined_r:unconfined_t:",
|
297
|
+
":object_r:passenger_instance_httpd_socket_t:");
|
298
|
+
if (setsockcreatecon((security_context_t) newCon.c_str()) == -1) {
|
299
|
+
e = errno;
|
300
|
+
P_WARN("Cannot set SELinux socket context to " << newCon <<
|
301
|
+
": " << strerror(e) << " (errno=" << e << ")");
|
302
|
+
goto cleanup;
|
303
|
+
}
|
304
|
+
|
305
|
+
cleanup:
|
306
|
+
freecon(currentCon);
|
307
|
+
}
|
308
|
+
|
309
|
+
static void
|
310
|
+
resetSelinuxSocketContext() {
|
311
|
+
setsockcreatecon(NULL);
|
312
|
+
}
|
313
|
+
#endif
|
314
|
+
|
271
315
|
static void
|
272
316
|
startListening() {
|
273
317
|
TRACE_POINT();
|
@@ -275,9 +319,18 @@ startListening() {
|
|
275
319
|
vector<string> addresses = agentsOptions->getStrSet("server_addresses");
|
276
320
|
vector<string> adminAddresses = agentsOptions->getStrSet("server_admin_addresses", false);
|
277
321
|
|
322
|
+
#ifdef USE_SELINUX
|
323
|
+
// Set SELinux context on the first socket that we create
|
324
|
+
// so that the web server can access it.
|
325
|
+
setSelinuxSocketContext();
|
326
|
+
#endif
|
327
|
+
|
278
328
|
for (unsigned int i = 0; i < addresses.size(); i++) {
|
279
329
|
wo->serverFds[i] = createServer(addresses[i], 0, true,
|
280
330
|
__FILE__, __LINE__);
|
331
|
+
#ifdef USE_SELINUX
|
332
|
+
resetSelinuxSocketContext();
|
333
|
+
#endif
|
281
334
|
P_LOG_FILE_DESCRIPTOR_PURPOSE(wo->serverFds[i],
|
282
335
|
"Server address: " << addresses[i]);
|
283
336
|
if (getSocketAddressType(addresses[i]) == SAT_UNIX) {
|
@@ -150,6 +150,8 @@ private:
|
|
150
150
|
HashedStaticString HTTP_CONNECTION;
|
151
151
|
HashedStaticString HTTP_STATUS;
|
152
152
|
HashedStaticString HTTP_TRANSFER_ENCODING;
|
153
|
+
HashedStaticString HTTP_X_SENDFILE;
|
154
|
+
HashedStaticString HTTP_X_ACCEL_REDIRECT;
|
153
155
|
|
154
156
|
unsigned int threadNumber;
|
155
157
|
StaticString serverLogName;
|
@@ -215,6 +217,8 @@ public:
|
|
215
217
|
HTTP_CONNECTION("connection"),
|
216
218
|
HTTP_STATUS("status"),
|
217
219
|
HTTP_TRANSFER_ENCODING("transfer-encoding"),
|
220
|
+
HTTP_X_SENDFILE("x-sendfile"),
|
221
|
+
HTTP_X_ACCEL_REDIRECT("x-accel-redirect"),
|
218
222
|
|
219
223
|
threadNumber(_threadNumber),
|
220
224
|
turboCaching(getTurboCachingInitialState(_agentsOptions))
|
@@ -335,6 +335,12 @@ onAppResponseBegin(Client *client, Request *req) {
|
|
335
335
|
req->wantKeepAlive = false;
|
336
336
|
}
|
337
337
|
}
|
338
|
+
if (resp->headers.lookup(HTTP_X_SENDFILE) != NULL
|
339
|
+
|| resp->headers.lookup(HTTP_X_ACCEL_REDIRECT) != NULL)
|
340
|
+
{
|
341
|
+
// https://github.com/phusion/passenger/issues/1498
|
342
|
+
resp->wantKeepAlive = false;
|
343
|
+
}
|
338
344
|
|
339
345
|
prepareAppResponseCaching(client, req);
|
340
346
|
|
@@ -433,7 +433,7 @@ pre_config_init(ngx_conf_t *cf)
|
|
433
433
|
*/
|
434
434
|
static ngx_int_t
|
435
435
|
init_module(ngx_cycle_t *cycle) {
|
436
|
-
if (passenger_main_conf.root_dir.len != 0) {
|
436
|
+
if (passenger_main_conf.root_dir.len != 0 && !ngx_test_config) {
|
437
437
|
if (first_start) {
|
438
438
|
/* Ignore SIGPIPE now so that, if the helper server fails to start,
|
439
439
|
* Nginx doesn't get killed by the default SIGPIPE handler upon
|
@@ -463,7 +463,7 @@ static ngx_int_t
|
|
463
463
|
init_worker_process(ngx_cycle_t *cycle) {
|
464
464
|
ngx_core_conf_t *core_conf;
|
465
465
|
|
466
|
-
if (passenger_main_conf.root_dir.len != 0) {
|
466
|
+
if (passenger_main_conf.root_dir.len != 0 && !ngx_test_config) {
|
467
467
|
save_master_process_pid(cycle);
|
468
468
|
|
469
469
|
core_conf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
|
data/lib/phusion_passenger.rb
CHANGED
@@ -30,7 +30,7 @@ module PhusionPassenger
|
|
30
30
|
|
31
31
|
PACKAGE_NAME = 'passenger'
|
32
32
|
# Run 'rake ext/common/Constants.h' after changing this number.
|
33
|
-
VERSION_STRING = '5.0.
|
33
|
+
VERSION_STRING = '5.0.8'
|
34
34
|
|
35
35
|
PREFERRED_NGINX_VERSION = '1.6.3'
|
36
36
|
NGINX_SHA256_CHECKSUM = '0a98e95b366e4d6042f331e1fa4d70e18fd1e49d8993e589008e70e742b7e757'
|
@@ -149,7 +149,20 @@ module PhusionPassenger
|
|
149
149
|
# method was used. Can be 'deb', 'rpm', 'homebrew', 'test'
|
150
150
|
# or 'unknown'.
|
151
151
|
def self.packaging_method
|
152
|
-
return @
|
152
|
+
return @packaging_method
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.packaging_method_description
|
156
|
+
case packaging_method
|
157
|
+
when "deb"
|
158
|
+
"Debian packages"
|
159
|
+
when "rpm"
|
160
|
+
"RPM packages"
|
161
|
+
when "homebrew"
|
162
|
+
"Homebrew"
|
163
|
+
else
|
164
|
+
"gem or tarball"
|
165
|
+
end
|
153
166
|
end
|
154
167
|
|
155
168
|
# Whether the current Phusion Passenger installation is installed
|
@@ -29,38 +29,42 @@ module PhusionPassenger
|
|
29
29
|
module AdminTools
|
30
30
|
|
31
31
|
class InstanceRegistry
|
32
|
-
def initialize(
|
33
|
-
@
|
32
|
+
def initialize(paths = nil)
|
33
|
+
@paths = [paths || default_paths].flatten
|
34
34
|
end
|
35
35
|
|
36
36
|
def list(options = {})
|
37
37
|
options = {
|
38
38
|
:clean_stale_or_corrupted => true
|
39
39
|
}.merge(options)
|
40
|
+
|
40
41
|
instances = []
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
43
|
+
@paths.each do |path|
|
44
|
+
Dir["#{path}/passenger.*"].each do |dir|
|
45
|
+
instance = Instance.new(dir)
|
46
|
+
case instance.state
|
47
|
+
when :good
|
48
|
+
if instance.locked?
|
49
|
+
instances << instance
|
50
|
+
elsif options[:clean_stale_or_corrupted]
|
51
|
+
cleanup(dir)
|
52
|
+
end
|
53
|
+
when :structure_version_unsupported
|
54
|
+
next
|
55
|
+
when :corrupted
|
56
|
+
if !instance.locked? && options[:clean_stale_or_corrupted]
|
57
|
+
cleanup(dir)
|
58
|
+
end
|
59
|
+
when :not_finalized
|
60
|
+
if instance.stale? && options[:clean_stale_or_corrupted]
|
61
|
+
cleanup(dir)
|
62
|
+
end
|
60
63
|
end
|
61
64
|
end
|
62
65
|
end
|
63
|
-
|
66
|
+
|
67
|
+
instances
|
64
68
|
end
|
65
69
|
|
66
70
|
def find_by_name(name, options = {})
|
@@ -78,13 +82,22 @@ module PhusionPassenger
|
|
78
82
|
end
|
79
83
|
|
80
84
|
private
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
def default_paths
|
86
|
+
if result = string_env("PASSENGER_INSTANCE_REGISTRY_DIR")
|
87
|
+
return result
|
88
|
+
end
|
89
|
+
|
90
|
+
# The RPM packages configure Apache and Nginx to use /var/run/passenger-instreg
|
91
|
+
# as the instance registry dir. See https://github.com/phusion/passenger/issues/1475
|
92
|
+
[string_env("TMPDIR") || "/tmp", "/var/run/passenger-instreg"]
|
93
|
+
end
|
94
|
+
|
95
|
+
def string_env(name)
|
96
|
+
if (result = ENV[name]) && !result.empty?
|
97
|
+
result
|
98
|
+
else
|
99
|
+
nil
|
86
100
|
end
|
87
|
-
return "/tmp"
|
88
101
|
end
|
89
102
|
|
90
103
|
def cleanup(path)
|