passenger 4.0.48 → 4.0.49
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/.editorconfig +36 -2
- data/.travis.yml +1 -1
- data/CHANGELOG +16 -0
- data/Rakefile +0 -1
- data/build/apache2.rb +4 -4
- data/build/common_library.rb +18 -18
- data/build/cplusplus_support.rb +2 -2
- data/build/documentation.rb +1 -1
- data/build/integration_tests.rb +12 -4
- data/build/misc.rb +12 -7
- data/build/packaging.rb +14 -14
- data/build/preprocessor.rb +10 -10
- data/build/rake_extensions.rb +11 -11
- data/build/ruby_extension.rb +2 -2
- data/dev/ci/inituidgid +24 -0
- data/dev/ci/run_jenkins.sh +57 -0
- data/dev/ci/run_rpm_tests.sh +77 -0
- data/dev/{run_travis.sh → ci/run_travis.sh} +60 -4
- data/doc/Users guide Nginx.txt +2 -2
- data/doc/users_guide_snippets/environment_variables.txt +0 -2
- data/doc/users_guide_snippets/tips.txt +20 -1
- data/ext/apache2/Bucket.cpp +18 -18
- data/ext/apache2/Bucket.h +4 -4
- data/ext/apache2/Configuration.cpp +7 -7
- data/ext/apache2/Configuration.hpp +43 -43
- data/ext/apache2/DirectoryMapper.h +5 -5
- data/ext/apache2/Hooks.cpp +142 -142
- data/ext/apache2/MergeDirConfig.cpp +40 -40
- data/ext/common/Account.h +17 -17
- data/ext/common/AccountsDatabase.h +9 -9
- data/ext/common/AgentsStarter.cpp +2 -2
- data/ext/common/AgentsStarter.h +40 -40
- data/ext/common/ApplicationPool2/Common.h +10 -6
- data/ext/common/ApplicationPool2/ComponentInfo.h +2 -2
- data/ext/common/ApplicationPool2/DirectSpawner.h +17 -17
- data/ext/common/ApplicationPool2/DummySpawner.h +5 -5
- data/ext/common/ApplicationPool2/Group.h +54 -38
- data/ext/common/ApplicationPool2/Implementation.cpp +76 -49
- data/ext/common/ApplicationPool2/Options.h +98 -91
- data/ext/common/ApplicationPool2/Pool.h +70 -69
- data/ext/common/ApplicationPool2/Process.h +21 -21
- data/ext/common/ApplicationPool2/Session.h +11 -11
- data/ext/common/ApplicationPool2/SmartSpawner.h +60 -60
- data/ext/common/ApplicationPool2/Socket.h +19 -19
- data/ext/common/ApplicationPool2/Spawner.h +64 -72
- data/ext/common/ApplicationPool2/SpawnerFactory.h +4 -4
- data/ext/common/ApplicationPool2/SuperGroup.h +41 -41
- data/ext/common/BackgroundEventLoop.cpp +1 -1
- data/ext/common/BackgroundEventLoop.h +2 -2
- data/ext/common/Constants.h +1 -1
- data/ext/common/EventedBufferedInput.h +5 -5
- data/ext/common/EventedClient.h +51 -51
- data/ext/common/EventedMessageServer.h +39 -39
- data/ext/common/EventedServer.h +32 -32
- data/ext/common/Exceptions.h +23 -23
- data/ext/common/FileDescriptor.h +18 -18
- data/ext/common/Logging.cpp +1 -1
- data/ext/common/MessageClient.h +27 -27
- data/ext/common/MessageReadersWriters.h +79 -79
- data/ext/common/MessageServer.h +59 -59
- data/ext/common/RandomGenerator.h +12 -12
- data/ext/common/ResourceLocator.h +8 -8
- data/ext/common/SafeLibev.h +54 -25
- data/ext/common/ServerInstanceDir.h +31 -31
- data/ext/common/StaticString.h +50 -48
- data/ext/common/Utils.cpp +73 -78
- data/ext/common/Utils.h +6 -6
- data/ext/common/Utils/Base64.cpp +3 -3
- data/ext/common/Utils/Base64.h +7 -7
- data/ext/common/Utils/BlockingQueue.h +9 -9
- data/ext/common/Utils/BufferedIO.h +17 -17
- data/ext/common/Utils/CachedFileStat.hpp +16 -16
- data/ext/common/Utils/Dechunker.h +25 -25
- data/ext/common/Utils/FileChangeChecker.h +10 -10
- data/ext/common/Utils/MemZeroGuard.h +5 -5
- data/ext/common/Utils/MemoryBarrier.h +1 -1
- data/ext/common/Utils/MessageIO.h +61 -61
- data/ext/common/Utils/ProcessMetricsCollector.h +40 -40
- data/ext/common/Utils/ScopeGuard.h +7 -7
- data/ext/common/Utils/SpeedMeter.h +1 -1
- data/ext/common/Utils/StrIntUtils.cpp +13 -13
- data/ext/common/Utils/StrIntUtils.h +3 -3
- data/ext/common/Utils/StringScanning.h +5 -5
- data/ext/common/Utils/SystemMetricsCollector.h +2 -2
- data/ext/common/Utils/SystemTime.h +10 -10
- data/ext/common/Utils/Template.h +2 -2
- data/ext/common/Utils/Timer.h +6 -6
- data/ext/common/Utils/VariantMap.h +29 -29
- data/ext/common/agents/Base.cpp +19 -19
- data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
- data/ext/common/agents/HelperAgent/FileBackedPipe.h +6 -6
- data/ext/common/agents/HelperAgent/Main.cpp +44 -43
- data/ext/common/agents/HelperAgent/RequestHandler.cpp +4 -4
- data/ext/common/agents/HelperAgent/RequestHandler.h +29 -28
- data/ext/common/agents/HelperAgent/ScgiRequestParser.h +56 -50
- data/ext/common/agents/LoggingAgent/AdminController.h +8 -8
- data/ext/common/agents/LoggingAgent/DataStoreId.h +17 -17
- data/ext/common/agents/LoggingAgent/FilterSupport.h +167 -167
- data/ext/common/agents/LoggingAgent/LoggingServer.h +122 -122
- data/ext/common/agents/LoggingAgent/Main.cpp +7 -7
- data/ext/common/agents/LoggingAgent/RemoteSender.h +54 -54
- data/ext/common/agents/SpawnPreparer.cpp +4 -4
- data/ext/common/agents/TempDirToucher.c +2 -2
- data/ext/common/agents/Watchdog/AgentWatcher.cpp +47 -47
- data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +7 -7
- data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +7 -7
- data/ext/common/agents/Watchdog/Main.cpp +22 -22
- data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +9 -9
- data/ext/libeio/eio.c +1 -1
- data/ext/nginx/Configuration.c +30 -30
- data/ext/nginx/Configuration.h +1 -1
- data/ext/nginx/ContentHandler.c +54 -54
- data/ext/nginx/ContentHandler.h +3 -3
- data/ext/nginx/StaticContentHandler.c +2 -2
- data/ext/nginx/ngx_http_passenger_module.c +21 -21
- data/ext/oxt/detail/backtrace_enabled.hpp +1 -1
- data/ext/oxt/detail/context.hpp +1 -1
- data/ext/oxt/detail/spin_lock_darwin.hpp +4 -4
- data/ext/oxt/detail/spin_lock_gcc_x86.hpp +3 -3
- data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
- data/ext/oxt/detail/tracable_exception_disabled.hpp +1 -1
- data/ext/oxt/dynamic_thread_group.hpp +18 -18
- data/ext/oxt/implementation.cpp +9 -8
- data/ext/oxt/macros.hpp +2 -2
- data/ext/oxt/system_calls.cpp +11 -11
- data/ext/oxt/system_calls.hpp +13 -13
- data/ext/oxt/thread.hpp +22 -14
- data/ext/ruby/passenger_native_support.c +55 -55
- data/lib/phusion_passenger.rb +24 -24
- data/lib/phusion_passenger/common_library.rb +2 -0
- data/lib/phusion_passenger/loader_shared_helpers.rb +18 -18
- data/lib/phusion_passenger/packaging.rb +9 -4
- data/lib/phusion_passenger/platform_info/apache.rb +45 -31
- data/lib/phusion_passenger/platform_info/compiler.rb +11 -11
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
- data/lib/phusion_passenger/request_handler/thread_handler.rb +8 -8
- data/lib/phusion_passenger/standalone/app_finder.rb +16 -16
- data/lib/phusion_passenger/standalone/command.rb +22 -22
- data/packaging/rpm/LICENSE.txt +19 -0
- data/packaging/rpm/Makefile +13 -0
- data/packaging/rpm/README.md +41 -0
- data/packaging/rpm/Vagrantfile +38 -0
- data/{rpm/Vagrantfile → packaging/rpm/Vagrantfile.centos} +0 -0
- data/packaging/rpm/build +170 -0
- data/packaging/rpm/create_project +41 -0
- data/packaging/rpm/git_update +88 -0
- data/packaging/rpm/image/Dockerfile +37 -0
- data/packaging/rpm/image/Gemfile +3 -0
- data/packaging/rpm/image/Gemfile.lock +12 -0
- data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +19 -0
- data/packaging/rpm/image/amazon2014-i386.cfg +96 -0
- data/packaging/rpm/image/amazon2014-x86_64.cfg +96 -0
- data/packaging/rpm/image/site-defaults.cfg +168 -0
- data/packaging/rpm/internal/build_tasks.rb +238 -0
- data/packaging/rpm/internal/dummygpg +11 -0
- data/packaging/rpm/internal/exec_build +42 -0
- data/packaging/rpm/internal/get_distro_arch +14 -0
- data/packaging/rpm/internal/get_distro_id +10 -0
- data/packaging/rpm/internal/git_update +27 -0
- data/packaging/rpm/internal/inituidgid +17 -0
- data/packaging/rpm/internal/my_init +344 -0
- data/packaging/rpm/internal/python27 +3 -0
- data/packaging/rpm/internal/repo_update +46 -0
- data/packaging/rpm/internal/setuser +26 -0
- data/packaging/rpm/internal/tracking_helper +40 -0
- data/packaging/rpm/jenkins_release +99 -0
- data/packaging/rpm/lib/build_tasks_support.rb +402 -0
- data/packaging/rpm/lib/preprocessor.rb +341 -0
- data/packaging/rpm/nginx_spec/404.html +119 -0
- data/packaging/rpm/nginx_spec/50x.html +119 -0
- data/packaging/rpm/nginx_spec/index.html +116 -0
- data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +13 -0
- data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
- data/packaging/rpm/nginx_spec/nginx-upgrade +13 -0
- data/packaging/rpm/nginx_spec/nginx-upgrade.8 +151 -0
- data/packaging/rpm/nginx_spec/nginx.conf +131 -0
- data/packaging/rpm/nginx_spec/nginx.init +144 -0
- data/packaging/rpm/nginx_spec/nginx.logrotate +13 -0
- data/packaging/rpm/nginx_spec/nginx.service +15 -0
- data/packaging/rpm/nginx_spec/nginx.spec.template +559 -0
- data/packaging/rpm/nginx_spec/nginx.sysconfig +4 -0
- data/packaging/rpm/nginx_spec/passenger.conf +9 -0
- data/packaging/rpm/nginx_spec/poweredby.png +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/apache-passenger.conf.in +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/config.json +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/passenger.logrotate +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/passenger.spec.template +58 -31
- data/{rpm → packaging/rpm/passenger_spec}/passenger_dynamic_thread_group.patch +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/passenger_tests_default_config_example.patch +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +0 -0
- data/packaging/rpm/repo_update +114 -0
- data/packaging/rpm/setup-system +60 -0
- data/packaging/rpm/shell +10 -0
- data/resources/templates/standalone/config.erb +3 -1
- data/test/config.json.rpm-automation +1 -1
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +11 -11
- data/test/cxx/ApplicationPool2/OptionsTest.cpp +5 -5
- data/test/cxx/ApplicationPool2/PoolTest.cpp +129 -89
- data/test/cxx/ApplicationPool2/ProcessTest.cpp +15 -15
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +22 -22
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +11 -11
- data/test/cxx/ScgiRequestParserTest.cpp +75 -61
- data/test/cxx/UtilsTest.cpp +86 -85
- data/test/gdbinit.example +3 -0
- data/test/integration_tests/nginx_tests.rb +3 -3
- data/test/integration_tests/source_packaging_test.rb +3 -1
- data/test/stub/nginx/nginx.conf.erb +8 -1
- data/test/support/nginx_controller.rb +7 -7
- metadata +62 -17
- metadata.gz.asc +7 -7
- data/build/rpm.rb +0 -128
- data/dev/rpmtool +0 -21
- data/dev/test_rpm_packaging.sh +0 -28
- data/rpm/get_distro_id.py +0 -4
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# A wrapper around gpg that makes gpg non-interactive, and makes it
|
3
|
+
# read a passphrase from the passphrase configuration file. To use
|
4
|
+
# this wrapper, prepend the containing directory to PATH.
|
5
|
+
|
6
|
+
set -e
|
7
|
+
if [[ "$1" == "--version" ]]; then
|
8
|
+
exec /usr/bin/gpg2.real --version
|
9
|
+
else
|
10
|
+
exec /usr/bin/gpg2.real --batch --passphrase-fd 3 "$@" 3<"/params/signing_passphrase"
|
11
|
+
fi
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
|
4
|
+
function verbose_run()
|
5
|
+
{
|
6
|
+
if $VERBOSE; then
|
7
|
+
echo "$ $@"
|
8
|
+
fi
|
9
|
+
"$@"
|
10
|
+
}
|
11
|
+
|
12
|
+
verbose_run /system/internal/inituidgid
|
13
|
+
|
14
|
+
if [[ ! -e /cache ]]; then
|
15
|
+
verbose_run mkdir /cache
|
16
|
+
verbose_run chown app: /cache
|
17
|
+
fi
|
18
|
+
|
19
|
+
verbose_run /system/internal/setuser app \
|
20
|
+
mkdir -p "/output/log" "/cache/mock_cache" "/cache/mock_lib"
|
21
|
+
verbose_run /system/internal/setuser app rm -rf /output/log/*
|
22
|
+
if $CLEAN; then
|
23
|
+
verbose_run /system/internal/setuser app rm -rf /output/*-*
|
24
|
+
fi
|
25
|
+
|
26
|
+
verbose_run rm -rf /var/lib/mock
|
27
|
+
verbose_run ln -s /cache/mock_lib /var/lib/mock
|
28
|
+
verbose_run rm -rf /var/cache/mock
|
29
|
+
verbose_run ln -s /cache/mock_cache /var/cache/mock
|
30
|
+
verbose_run chown root:mock /cache/mock_cache
|
31
|
+
verbose_run chown root:mock /cache/mock_lib
|
32
|
+
|
33
|
+
export BUNDLE_GEMFILE=/home/app/Gemfile
|
34
|
+
|
35
|
+
if [[ "$TASK" != -T ]]; then
|
36
|
+
TASK="$TASK finish"
|
37
|
+
fi
|
38
|
+
|
39
|
+
verbose_run exec /system/internal/my_init --skip-runit --skip-startup-files --quiet -- \
|
40
|
+
/system/internal/setuser app \
|
41
|
+
bundle exec drake -j$CONCURRENCY -f /system/internal/build_tasks.rb \
|
42
|
+
$TASK --trace
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
import os.path, sys
|
3
|
+
|
4
|
+
if not os.path.isfile('/etc/mock/default.cfg'):
|
5
|
+
sys.stderr.write("This does not seem to be a Red Hat compatible OS.\n")
|
6
|
+
exit(1)
|
7
|
+
|
8
|
+
vars = { 'config_opts': {} }
|
9
|
+
execfile("/etc/mock/default.cfg", vars)
|
10
|
+
arch = vars['config_opts']['target_arch']
|
11
|
+
if arch == 'i386' or arch == 'i586' or arch == 'i686':
|
12
|
+
print('i386')
|
13
|
+
else:
|
14
|
+
print(arch)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
import os.path, sys
|
3
|
+
|
4
|
+
if not os.path.isfile('/etc/mock/default.cfg'):
|
5
|
+
sys.stderr.write("This does not seem to be a Red Hat compatible OS.\n")
|
6
|
+
exit(1)
|
7
|
+
|
8
|
+
vars = { 'config_opts': {} }
|
9
|
+
execfile("/etc/mock/default.cfg", vars)
|
10
|
+
print(vars['config_opts']['dist'])
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
|
4
|
+
function run_quiet()
|
5
|
+
{
|
6
|
+
/system/internal/setuser app "$@"
|
7
|
+
}
|
8
|
+
|
9
|
+
function run()
|
10
|
+
{
|
11
|
+
echo " --> $@"
|
12
|
+
/system/internal/setuser app "$@"
|
13
|
+
}
|
14
|
+
|
15
|
+
/system/internal/inituidgid
|
16
|
+
|
17
|
+
cd /git
|
18
|
+
if [[ -e .git ]]; then
|
19
|
+
run_quiet rm -rf *
|
20
|
+
run git fetch
|
21
|
+
else
|
22
|
+
run git clone "$GIT_URL" .
|
23
|
+
fi
|
24
|
+
if [[ -e .gitmodules ]]; then
|
25
|
+
run git submodule update --init --recursive
|
26
|
+
fi
|
27
|
+
run git reset --hard "$GIT_REF"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
|
4
|
+
chown -R "$APP_UID:$APP_GID" /home/app
|
5
|
+
groupmod -g "$APP_GID" app
|
6
|
+
usermod -u "$APP_UID" -g "$APP_GID" app
|
7
|
+
|
8
|
+
# There's something strange with either Docker or the kernel, so that
|
9
|
+
# the 'app' user cannot access its home directory even after a proper
|
10
|
+
# chown/chmod. We work around it like this.
|
11
|
+
mv /home/app /home/app2
|
12
|
+
cp -dpR /home/app2 /home/app
|
13
|
+
rm -rf /home/app2
|
14
|
+
|
15
|
+
if [[ $# -gt 0 ]]; then
|
16
|
+
exec "$@"
|
17
|
+
fi
|
@@ -0,0 +1,344 @@
|
|
1
|
+
#!/system/internal/python27 -u
|
2
|
+
import os, os.path, sys, stat, signal, errno, argparse, time, json, re
|
3
|
+
|
4
|
+
KILL_PROCESS_TIMEOUT = 5
|
5
|
+
KILL_ALL_PROCESSES_TIMEOUT = 5
|
6
|
+
|
7
|
+
LOG_LEVEL_ERROR = 1
|
8
|
+
LOG_LEVEL_WARN = 1
|
9
|
+
LOG_LEVEL_INFO = 2
|
10
|
+
LOG_LEVEL_DEBUG = 3
|
11
|
+
|
12
|
+
log_level = None
|
13
|
+
|
14
|
+
terminated_child_processes = {}
|
15
|
+
|
16
|
+
class AlarmException(Exception):
|
17
|
+
pass
|
18
|
+
|
19
|
+
def error(message):
|
20
|
+
if log_level >= LOG_LEVEL_ERROR:
|
21
|
+
sys.stderr.write("*** %s\n" % message)
|
22
|
+
|
23
|
+
def warn(message):
|
24
|
+
if log_level >= LOG_LEVEL_WARN:
|
25
|
+
sys.stderr.write("*** %s\n" % message)
|
26
|
+
|
27
|
+
def info(message):
|
28
|
+
if log_level >= LOG_LEVEL_INFO:
|
29
|
+
sys.stderr.write("*** %s\n" % message)
|
30
|
+
|
31
|
+
def debug(message):
|
32
|
+
if log_level >= LOG_LEVEL_DEBUG:
|
33
|
+
sys.stderr.write("*** %s\n" % message)
|
34
|
+
|
35
|
+
def ignore_signals_and_raise_keyboard_interrupt(signame):
|
36
|
+
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
37
|
+
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
38
|
+
raise KeyboardInterrupt(signame)
|
39
|
+
|
40
|
+
def raise_alarm_exception():
|
41
|
+
raise AlarmException('Alarm')
|
42
|
+
|
43
|
+
def listdir(path):
|
44
|
+
try:
|
45
|
+
result = os.stat(path)
|
46
|
+
except OSError:
|
47
|
+
return []
|
48
|
+
if stat.S_ISDIR(result.st_mode):
|
49
|
+
return sorted(os.listdir(path))
|
50
|
+
else:
|
51
|
+
return []
|
52
|
+
|
53
|
+
def is_exe(path):
|
54
|
+
try:
|
55
|
+
return os.path.isfile(path) and os.access(path, os.X_OK)
|
56
|
+
except OSError:
|
57
|
+
return False
|
58
|
+
|
59
|
+
def create_hosts_file():
|
60
|
+
run_command_killable("/bin/cp", "/etc/hosts", "/etc/workaround-docker-2267/")
|
61
|
+
|
62
|
+
def import_envvars(clear_existing_environment = True, override_existing_environment = True):
|
63
|
+
new_env = {}
|
64
|
+
for envfile in listdir("/etc/container_environment"):
|
65
|
+
name = os.path.basename(envfile)
|
66
|
+
with open("/etc/container_environment/" + envfile, "r") as f:
|
67
|
+
# Text files often end with a trailing newline, which we
|
68
|
+
# don't want to include in the env variable value. See
|
69
|
+
# https://github.com/phusion/baseimage-docker/pull/49
|
70
|
+
value = re.sub('\n\Z', '', f.read())
|
71
|
+
new_env[name] = value
|
72
|
+
if clear_existing_environment:
|
73
|
+
os.environ.clear()
|
74
|
+
for name, value in new_env.items():
|
75
|
+
if override_existing_environment or not name in os.environ:
|
76
|
+
os.environ[name] = value
|
77
|
+
|
78
|
+
def export_envvars(to_dir = True):
|
79
|
+
shell_dump = ""
|
80
|
+
for name, value in os.environ.items():
|
81
|
+
if name in ['HOME', 'USER', 'GROUP', 'UID', 'GID', 'SHELL']:
|
82
|
+
continue
|
83
|
+
if to_dir:
|
84
|
+
with open("/etc/container_environment/" + name, "w") as f:
|
85
|
+
f.write(value)
|
86
|
+
shell_dump += "export " + shquote(name) + "=" + shquote(value) + "\n"
|
87
|
+
with open("/etc/container_environment.sh", "w") as f:
|
88
|
+
f.write(shell_dump)
|
89
|
+
with open("/etc/container_environment.json", "w") as f:
|
90
|
+
f.write(json.dumps(dict(os.environ)))
|
91
|
+
|
92
|
+
_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search
|
93
|
+
|
94
|
+
def shquote(s):
|
95
|
+
"""Return a shell-escaped version of the string *s*."""
|
96
|
+
if not s:
|
97
|
+
return "''"
|
98
|
+
if _find_unsafe(s) is None:
|
99
|
+
return s
|
100
|
+
|
101
|
+
# use single quotes, and put single quotes into double quotes
|
102
|
+
# the string $'b is then quoted as '$'"'"'b'
|
103
|
+
return "'" + s.replace("'", "'\"'\"'") + "'"
|
104
|
+
|
105
|
+
# Waits for the child process with the given PID, while at the same time
|
106
|
+
# reaping any other child processes that have exited (e.g. adopted child
|
107
|
+
# processes that have terminated).
|
108
|
+
def waitpid_reap_other_children(pid):
|
109
|
+
global terminated_child_processes
|
110
|
+
|
111
|
+
status = terminated_child_processes.get(pid)
|
112
|
+
if status:
|
113
|
+
# A previous call to waitpid_reap_other_children(),
|
114
|
+
# with an argument not equal to the current argument,
|
115
|
+
# already waited for this process. Return the status
|
116
|
+
# that was obtained back then.
|
117
|
+
del terminated_child_processes[pid]
|
118
|
+
return status
|
119
|
+
|
120
|
+
done = False
|
121
|
+
status = None
|
122
|
+
while not done:
|
123
|
+
try:
|
124
|
+
this_pid, status = os.waitpid(-1, 0)
|
125
|
+
if this_pid == pid:
|
126
|
+
done = True
|
127
|
+
else:
|
128
|
+
# Save status for later.
|
129
|
+
terminated_child_processes[this_pid] = status
|
130
|
+
except OSError as e:
|
131
|
+
if e.errno == errno.ECHILD or e.errno == errno.ESRCH:
|
132
|
+
return None
|
133
|
+
else:
|
134
|
+
raise
|
135
|
+
return status
|
136
|
+
|
137
|
+
def stop_child_process(name, pid, signo = signal.SIGTERM, time_limit = KILL_PROCESS_TIMEOUT):
|
138
|
+
info("Shutting down %s (PID %d)..." % (name, pid))
|
139
|
+
try:
|
140
|
+
os.kill(pid, signo)
|
141
|
+
except OSError:
|
142
|
+
pass
|
143
|
+
signal.alarm(time_limit)
|
144
|
+
try:
|
145
|
+
try:
|
146
|
+
waitpid_reap_other_children(pid)
|
147
|
+
except OSError:
|
148
|
+
pass
|
149
|
+
except AlarmException:
|
150
|
+
warn("%s (PID %d) did not shut down in time. Forcing it to exit." % (name, pid))
|
151
|
+
try:
|
152
|
+
os.kill(pid, signal.SIGKILL)
|
153
|
+
except OSError:
|
154
|
+
pass
|
155
|
+
try:
|
156
|
+
waitpid_reap_other_children(pid)
|
157
|
+
except OSError:
|
158
|
+
pass
|
159
|
+
finally:
|
160
|
+
signal.alarm(0)
|
161
|
+
|
162
|
+
def run_command_killable(*argv):
|
163
|
+
filename = argv[0]
|
164
|
+
status = None
|
165
|
+
pid = os.spawnvp(os.P_NOWAIT, filename, argv)
|
166
|
+
try:
|
167
|
+
status = waitpid_reap_other_children(pid)
|
168
|
+
except BaseException as s:
|
169
|
+
warn("An error occurred. Aborting.")
|
170
|
+
stop_child_process(filename, pid)
|
171
|
+
raise
|
172
|
+
if status != 0:
|
173
|
+
if status is None:
|
174
|
+
error("%s exited with unknown status\n" % filename)
|
175
|
+
else:
|
176
|
+
error("%s failed with status %d\n" % (filename, os.WEXITSTATUS(status)))
|
177
|
+
sys.exit(1)
|
178
|
+
|
179
|
+
def run_command_killable_and_import_envvars(*argv):
|
180
|
+
run_command_killable(*argv)
|
181
|
+
import_envvars()
|
182
|
+
export_envvars(False)
|
183
|
+
|
184
|
+
def kill_all_processes(time_limit):
|
185
|
+
info("Killing all processes...")
|
186
|
+
try:
|
187
|
+
os.kill(-1, signal.SIGTERM)
|
188
|
+
except OSError:
|
189
|
+
pass
|
190
|
+
signal.alarm(time_limit)
|
191
|
+
try:
|
192
|
+
# Wait until no more child processes exist.
|
193
|
+
done = False
|
194
|
+
while not done:
|
195
|
+
try:
|
196
|
+
os.waitpid(-1, 0)
|
197
|
+
except OSError as e:
|
198
|
+
if e.errno == errno.ECHILD:
|
199
|
+
done = True
|
200
|
+
else:
|
201
|
+
raise
|
202
|
+
except AlarmException:
|
203
|
+
warn("Not all processes have exited in time. Forcing them to exit.")
|
204
|
+
try:
|
205
|
+
os.kill(-1, signal.SIGKILL)
|
206
|
+
except OSError:
|
207
|
+
pass
|
208
|
+
finally:
|
209
|
+
signal.alarm(0)
|
210
|
+
|
211
|
+
def run_startup_files():
|
212
|
+
# Run /etc/my_init.d/*
|
213
|
+
for name in listdir("/etc/my_init.d"):
|
214
|
+
filename = "/etc/my_init.d/" + name
|
215
|
+
if is_exe(filename):
|
216
|
+
info("Running %s..." % filename)
|
217
|
+
run_command_killable_and_import_envvars(filename)
|
218
|
+
|
219
|
+
# Run /etc/rc.local.
|
220
|
+
if is_exe("/etc/rc.local"):
|
221
|
+
info("Running /etc/rc.local...")
|
222
|
+
run_command_killable_and_import_envvars("/etc/rc.local")
|
223
|
+
|
224
|
+
def start_runit():
|
225
|
+
info("Booting runit daemon...")
|
226
|
+
pid = os.spawnl(os.P_NOWAIT, "/usr/bin/runsvdir", "/usr/bin/runsvdir",
|
227
|
+
"-P", "/etc/service")
|
228
|
+
info("Runit started as PID %d" % pid)
|
229
|
+
return pid
|
230
|
+
|
231
|
+
def wait_for_runit_or_interrupt(pid):
|
232
|
+
try:
|
233
|
+
status = waitpid_reap_other_children(pid)
|
234
|
+
return (True, status)
|
235
|
+
except KeyboardInterrupt:
|
236
|
+
return (False, None)
|
237
|
+
|
238
|
+
def shutdown_runit_services():
|
239
|
+
debug("Begin shutting down runit services...")
|
240
|
+
os.system("/usr/bin/sv down /etc/service/*")
|
241
|
+
|
242
|
+
def wait_for_runit_services():
|
243
|
+
debug("Waiting for runit services to exit...")
|
244
|
+
done = False
|
245
|
+
while not done:
|
246
|
+
done = os.system("/usr/bin/sv status /etc/service/* | grep -q '^run:'") != 0
|
247
|
+
if not done:
|
248
|
+
time.sleep(0.1)
|
249
|
+
|
250
|
+
def install_insecure_key():
|
251
|
+
info("Installing insecure SSH key for user root")
|
252
|
+
run_command_killable("/usr/sbin/enable_insecure_key")
|
253
|
+
|
254
|
+
def main(args):
|
255
|
+
create_hosts_file()
|
256
|
+
import_envvars(False, False)
|
257
|
+
export_envvars()
|
258
|
+
|
259
|
+
if args.enable_insecure_key:
|
260
|
+
install_insecure_key()
|
261
|
+
|
262
|
+
if not args.skip_startup_files:
|
263
|
+
run_startup_files()
|
264
|
+
|
265
|
+
runit_exited = False
|
266
|
+
exit_code = None
|
267
|
+
|
268
|
+
if not args.skip_runit:
|
269
|
+
runit_pid = start_runit()
|
270
|
+
try:
|
271
|
+
exit_status = None
|
272
|
+
if len(args.main_command) == 0:
|
273
|
+
runit_exited, exit_code = wait_for_runit_or_interrupt(runit_pid)
|
274
|
+
if runit_exited:
|
275
|
+
if exit_code is None:
|
276
|
+
info("Runit exited with unknown status")
|
277
|
+
exit_status = 1
|
278
|
+
else:
|
279
|
+
exit_status = os.WEXITSTATUS(exit_code)
|
280
|
+
info("Runit exited with status %d" % exit_status)
|
281
|
+
else:
|
282
|
+
info("Running %s..." % " ".join(args.main_command))
|
283
|
+
pid = os.spawnvp(os.P_NOWAIT, args.main_command[0], args.main_command)
|
284
|
+
try:
|
285
|
+
exit_code = waitpid_reap_other_children(pid)
|
286
|
+
if exit_code is None:
|
287
|
+
info("%s exited with unknown status." % args.main_command[0])
|
288
|
+
exit_status = 1
|
289
|
+
else:
|
290
|
+
exit_status = os.WEXITSTATUS(exit_code)
|
291
|
+
info("%s exited with status %d." % (args.main_command[0], exit_status))
|
292
|
+
except KeyboardInterrupt:
|
293
|
+
stop_child_process(args.main_command[0], pid)
|
294
|
+
raise
|
295
|
+
except BaseException as s:
|
296
|
+
warn("An error occurred. Aborting.")
|
297
|
+
stop_child_process(args.main_command[0], pid)
|
298
|
+
raise
|
299
|
+
sys.exit(exit_status)
|
300
|
+
finally:
|
301
|
+
if not args.skip_runit:
|
302
|
+
shutdown_runit_services()
|
303
|
+
if not runit_exited:
|
304
|
+
stop_child_process("runit daemon", runit_pid)
|
305
|
+
wait_for_runit_services()
|
306
|
+
|
307
|
+
# Parse options.
|
308
|
+
parser = argparse.ArgumentParser(description = 'Initialize the system.')
|
309
|
+
parser.add_argument('main_command', metavar = 'MAIN_COMMAND', type = str, nargs = '*',
|
310
|
+
help = 'The main command to run. (default: runit)')
|
311
|
+
parser.add_argument('--enable-insecure-key', dest = 'enable_insecure_key',
|
312
|
+
action = 'store_const', const = True, default = False,
|
313
|
+
help = 'Install the insecure SSH key')
|
314
|
+
parser.add_argument('--skip-startup-files', dest = 'skip_startup_files',
|
315
|
+
action = 'store_const', const = True, default = False,
|
316
|
+
help = 'Skip running /etc/my_init.d/* and /etc/rc.local')
|
317
|
+
parser.add_argument('--skip-runit', dest = 'skip_runit',
|
318
|
+
action = 'store_const', const = True, default = False,
|
319
|
+
help = 'Do not run runit services')
|
320
|
+
parser.add_argument('--no-kill-all-on-exit', dest = 'kill_all_on_exit',
|
321
|
+
action = 'store_const', const = False, default = True,
|
322
|
+
help = 'Don\'t kill all processes on the system upon exiting')
|
323
|
+
parser.add_argument('--quiet', dest = 'log_level',
|
324
|
+
action = 'store_const', const = LOG_LEVEL_WARN, default = LOG_LEVEL_INFO,
|
325
|
+
help = 'Only print warnings and errors')
|
326
|
+
args = parser.parse_args()
|
327
|
+
log_level = args.log_level
|
328
|
+
|
329
|
+
if args.skip_runit and len(args.main_command) == 0:
|
330
|
+
error("When --skip-runit is given, you must also pass a main command.")
|
331
|
+
sys.exit(1)
|
332
|
+
|
333
|
+
# Run main function.
|
334
|
+
signal.signal(signal.SIGTERM, lambda signum, frame: ignore_signals_and_raise_keyboard_interrupt('SIGTERM'))
|
335
|
+
signal.signal(signal.SIGINT, lambda signum, frame: ignore_signals_and_raise_keyboard_interrupt('SIGINT'))
|
336
|
+
signal.signal(signal.SIGALRM, lambda signum, frame: raise_alarm_exception())
|
337
|
+
try:
|
338
|
+
main(args)
|
339
|
+
except KeyboardInterrupt:
|
340
|
+
warn("Init system aborted.")
|
341
|
+
exit(2)
|
342
|
+
finally:
|
343
|
+
if args.kill_all_on_exit:
|
344
|
+
kill_all_processes(KILL_ALL_PROCESSES_TIMEOUT)
|