Skip to content

Commit

Permalink
Merge pull request #5373 from Icinga/feature/rlimit-options
Browse files Browse the repository at this point in the history
Make rlimits configurable by adding three variables: RLimitFiles, RLimitProcesses and RLimitStack

refs #5367
  • Loading branch information
Michael Friedrich committed Jun 23, 2017
2 parents 04757d1 + c8b4fee commit 0e423df
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 70 deletions.
15 changes: 13 additions & 2 deletions doc/17-language-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ Global constants can be set using the `const` keyword:
Once defined a constant can be accessed from any file. Constants cannot be changed
once they are set.

### <a id="icinga-constants"></a> Icinga 2 Specific Constants

Icinga 2 provides a number of special global constants. Some of them can be overridden using the `--define` command line parameter:

Variable |Description
Expand All @@ -383,8 +385,6 @@ ObjectsPath |**Read-write.** Contains the path of the Icinga 2 objects f
PidPath |**Read-write.** Contains the path of the Icinga 2 PID file. Defaults to RunDir + "/icinga2/icinga2.pid".
Vars |**Read-write.** Contains a dictionary with global custom attributes. Not set by default.
NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default.
EventEngine |**Read-write.** The name of the socket event engine, can be "poll" or "epoll". The epoll interface is only supported on Linux.
AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to false.
RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Used in the `init.conf` configuration file.
RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Used in the `init.conf` configuration file.
PlatformName |**Read-only.** The name of the operating system, e.g. "Ubuntu".
Expand All @@ -395,6 +395,17 @@ BuildCompilerName |**Read-only.** The name of the compiler Icinga was built wi
BuildCompilerVersion|**Read-only.** The version of the compiler Icinga was built with, e.g. "7.3.0.7030031".
BuildHostName |**Read-only.** The name of the host Icinga was built on, e.g. "acheron".


Advanced runtime constants. Please only use them if advised by support or developers.

Variable |Description
--------------------|-------------------
EventEngine |**Read-write.** The name of the socket event engine, can be `poll` or `epoll`. The epoll interface is only supported on Linux.
AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to `false`.
RLimitFiles |**Read-write.** Defines the resource limit for RLIMIT_NOFILE that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file.
RLimitProcesses |**Read-write.** Defines the resource limit for RLIMIT_NPROC that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file.
RLimitStack |**Read-write.** Defines the resource limit for RLIMIT_STACK that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file.

## <a id="apply"></a> Apply

The `apply` keyword can be used to create new objects which are associated with
Expand Down
49 changes: 27 additions & 22 deletions icinga-app/icinga.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ int Main(void)

Application::SetStartTime(Utility::GetTime());

if (!autocomplete)
Application::SetResourceLimits();

/* Set thread title. */
Utility::SetThreadName("Main Thread", false);

Expand Down Expand Up @@ -152,6 +149,11 @@ int Main(void)
Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d");
Application::DeclareRunAsUser(ICINGA_USER);
Application::DeclareRunAsGroup(ICINGA_GROUP);
#ifdef __linux__
Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles());
Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses());
Application::DeclareRLimitStack(Application::GetDefaultRLimitStack());
#endif /* __linux__ */
Application::DeclareConcurrency(boost::thread::hardware_concurrency());

ScriptGlobal::Set("AttachDebugger", false);
Expand All @@ -166,6 +168,28 @@ int Main(void)
ScriptGlobal::Set("BuildCompilerName", ICINGA_BUILD_COMPILER_NAME);
ScriptGlobal::Set("BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION);

String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf";

if (Utility::PathExists(initconfig)) {
Expression *expression;
try {
expression = ConfigCompiler::CompileFile(initconfig);

ScriptFrame frame;
expression->Evaluate(frame);
} catch (const std::exception& ex) {
delete expression;

Log(LogCritical, "config", DiagnosticInformation(ex));
return EXIT_FAILURE;
}

delete expression;
}

if (!autocomplete)
Application::SetResourceLimits();

LogSeverity logLevel = Logger::GetConsoleLogSeverity();
Logger::SetConsoleLogSeverity(LogWarning);

Expand Down Expand Up @@ -209,25 +233,6 @@ int Main(void)
return EXIT_FAILURE;
}

String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf";

if (Utility::PathExists(initconfig)) {
Expression *expression;
try {
expression = ConfigCompiler::CompileFile(initconfig);

ScriptFrame frame;
expression->Evaluate(frame);
} catch (const std::exception& ex) {
delete expression;

Log(LogCritical, "config", DiagnosticInformation(ex));
return EXIT_FAILURE;
}

delete expression;
}

#ifndef _WIN32
if (vm.count("color")) {
Console::SetType(std::cout, Console_VT100);
Expand Down
202 changes: 156 additions & 46 deletions lib/base/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,24 +180,44 @@ void Application::SetResourceLimits(void)
rlimit rl;

# ifdef RLIMIT_NOFILE
rl.rlim_cur = 16 * 1024;
rl.rlim_max = rl.rlim_cur;
rlim_t fileLimit = GetRLimitFiles();

if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
Log(LogNotice, "Application", "Could not adjust resource limit for open file handles (RLIMIT_NOFILE)");
if (fileLimit != 0) {
if (fileLimit < GetDefaultRLimitFiles()) {
Log(LogWarning, "Application")
<< "The user-specified value for RLimitFiles cannot be smaller than the default value (" << GetDefaultRLimitFiles() << "). Using the default value instead.";
fileLimit = GetDefaultRLimitFiles();
}

rl.rlim_cur = fileLimit;
rl.rlim_max = rl.rlim_cur;

if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
Log(LogNotice, "Application", "Could not adjust resource limit for open file handles (RLIMIT_NOFILE)");
# else /* RLIMIT_NOFILE */
Log(LogNotice, "Application", "System does not support adjusting the resource limit for open file handles (RLIMIT_NOFILE)");
Log(LogNotice, "Application", "System does not support adjusting the resource limit for open file handles (RLIMIT_NOFILE)");
# endif /* RLIMIT_NOFILE */
}

# ifdef RLIMIT_NPROC
rl.rlim_cur = 16 * 1024;
rl.rlim_max = rl.rlim_cur;
rlim_t processLimit = GetRLimitProcesses();

if (processLimit != 0) {
if (processLimit < GetDefaultRLimitProcesses()) {
Log(LogWarning, "Application")
<< "The user-specified value for RLimitProcesses cannot be smaller than the default value (" << GetDefaultRLimitProcesses() << "). Using the default value instead.";
processLimit = GetDefaultRLimitProcesses();
}

if (setrlimit(RLIMIT_NPROC, &rl) < 0)
Log(LogNotice, "Application", "Could not adjust resource limit for number of processes (RLIMIT_NPROC)");
rl.rlim_cur = processLimit;
rl.rlim_max = rl.rlim_cur;

if (setrlimit(RLIMIT_NPROC, &rl) < 0)
Log(LogNotice, "Application", "Could not adjust resource limit for number of processes (RLIMIT_NPROC)");
# else /* RLIMIT_NPROC */
Log(LogNotice, "Application", "System does not support adjusting the resource limit for number of processes (RLIMIT_NPROC)");
Log(LogNotice, "Application", "System does not support adjusting the resource limit for number of processes (RLIMIT_NPROC)");
# endif /* RLIMIT_NPROC */
}

# ifdef RLIMIT_STACK
int argc = Application::GetArgC();
Expand All @@ -216,41 +236,53 @@ void Application::SetResourceLimits(void)
rl.rlim_max = RLIM_INFINITY;
}

if (set_stack_rlimit)
rl.rlim_cur = 256 * 1024;
else
rl.rlim_cur = rl.rlim_max;
rlim_t stackLimit;

if (setrlimit(RLIMIT_STACK, &rl) < 0)
Log(LogNotice, "Application", "Could not adjust resource limit for stack size (RLIMIT_STACK)");
else if (set_stack_rlimit) {
char **new_argv = static_cast<char **>(malloc(sizeof(char *) * (argc + 2)));
stackLimit = GetRLimitStack();

if (!new_argv) {
perror("malloc");
Exit(EXIT_FAILURE);
if (stackLimit != 0) {
if (stackLimit < GetDefaultRLimitStack()) {
Log(LogWarning, "Application")
<< "The user-specified value for RLimitStack cannot be smaller than the default value (" << GetDefaultRLimitStack() << "). Using the default value instead.";
stackLimit = GetDefaultRLimitStack();
}

new_argv[0] = argv[0];
new_argv[1] = strdup("--no-stack-rlimit");
if (set_stack_rlimit)
rl.rlim_cur = stackLimit;
else
rl.rlim_cur = rl.rlim_max;

if (!new_argv[1]) {
perror("strdup");
exit(1);
}
if (setrlimit(RLIMIT_STACK, &rl) < 0)
Log(LogNotice, "Application", "Could not adjust resource limit for stack size (RLIMIT_STACK)");
else if (set_stack_rlimit) {
char **new_argv = static_cast<char **>(malloc(sizeof(char *) * (argc + 2)));

for (int i = 1; i < argc; i++)
new_argv[i + 1] = argv[i];
if (!new_argv) {
perror("malloc");
Exit(EXIT_FAILURE);
}

new_argv[argc + 1] = NULL;
new_argv[0] = argv[0];
new_argv[1] = strdup("--no-stack-rlimit");

(void) execvp(new_argv[0], new_argv);
perror("execvp");
_exit(EXIT_FAILURE);
}
if (!new_argv[1]) {
perror("strdup");
exit(1);
}

for (int i = 1; i < argc; i++)
new_argv[i + 1] = argv[i];

new_argv[argc + 1] = NULL;

(void) execvp(new_argv[0], new_argv);
perror("execvp");
_exit(EXIT_FAILURE);
}
# else /* RLIMIT_STACK */
Log(LogNotice, "Application", "System does not support adjusting the resource limit for stack size (RLIMIT_STACK)");
Log(LogNotice, "Application", "System does not support adjusting the resource limit for stack size (RLIMIT_STACK)");
# endif /* RLIMIT_STACK */
}
#endif /* __linux__ */
}

Expand Down Expand Up @@ -1331,6 +1363,95 @@ String Application::GetRunAsGroup(void)
return ScriptGlobal::Get("RunAsGroup");
}

/**
* Sets the name of the group.
*
* @param path The new group name.
*/
void Application::DeclareRunAsGroup(const String& group)
{
if (!ScriptGlobal::Exists("RunAsGroup"))
ScriptGlobal::Set("RunAsGroup", group);
}

/**
* Retrieves the file rlimit.
*
* @returns The limit.
*/
int Application::GetRLimitFiles(void)
{
return ScriptGlobal::Get("RLimitFiles");
}

int Application::GetDefaultRLimitFiles(void)
{
return 16 * 1024;
}

/**
* Sets the file rlimit.
*
* @param path The new file rlimit.
*/
void Application::DeclareRLimitFiles(int limit)
{
if (!ScriptGlobal::Exists("RLimitFiles"))
ScriptGlobal::Set("RLimitFiles", limit);
}

/**
* Retrieves the process rlimit.
*
* @returns The limit.
*/
int Application::GetRLimitProcesses(void)
{
return ScriptGlobal::Get("RLimitProcesses");
}

int Application::GetDefaultRLimitProcesses(void)
{
return 16 * 1024;
}

/**
* Sets the process rlimit.
*
* @param path The new process rlimit.
*/
void Application::DeclareRLimitProcesses(int limit)
{
if (!ScriptGlobal::Exists("RLimitProcesses"))
ScriptGlobal::Set("RLimitProcesses", limit);
}

/**
* Retrieves the stack rlimit.
*
* @returns The limit.
*/
int Application::GetRLimitStack(void)
{
return ScriptGlobal::Get("RLimitStack");
}

int Application::GetDefaultRLimitStack(void)
{
return 256 * 1024;
}

/**
* Sets the stack rlimit.
*
* @param path The new stack rlimit.
*/
void Application::DeclareRLimitStack(int limit)
{
if (!ScriptGlobal::Exists("RLimitStack"))
ScriptGlobal::Set("RLimitStack", limit);
}

/**
* Sets the concurrency level.
*
Expand All @@ -1353,17 +1474,6 @@ int Application::GetConcurrency(void)
return ScriptGlobal::Get("Concurrency", &defaultConcurrency);
}

/**
* Sets the name of the group.
*
* @param path The new group name.
*/
void Application::DeclareRunAsGroup(const String& group)
{
if (!ScriptGlobal::Exists("RunAsGroup"))
ScriptGlobal::Set("RunAsGroup", group);
}

/**
* Returns the global thread pool.
*
Expand Down
12 changes: 12 additions & 0 deletions lib/base/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ class I2_BASE_API Application : public ObjectImpl<Application> {
static String GetRunAsGroup(void);
static void DeclareRunAsGroup(const String& group);

static int GetRLimitFiles(void);
static int GetDefaultRLimitFiles(void);
static void DeclareRLimitFiles(int limit);

static int GetRLimitProcesses(void);
static int GetDefaultRLimitProcesses(void);
static void DeclareRLimitProcesses(int limit);

static int GetRLimitStack(void);
static int GetDefaultRLimitStack(void);
static void DeclareRLimitStack(int limit);

static int GetConcurrency(void);
static void DeclareConcurrency(int ncpus);

Expand Down

0 comments on commit 0e423df

Please sign in to comment.