mirror of https://github.com/Icinga/icinga2.git
parent
7a6172c135
commit
2034ff5eee
|
@ -2,8 +2,9 @@
|
|||
|
||||
## <a id="what-is-icinga2"></a> What is Icinga 2?
|
||||
|
||||
Icinga 2 is an open source monitoring system which keeps watch over network resources,
|
||||
notifies users of outages and recoveries and generates performance data for reporting.
|
||||
Icinga 2 is an open source monitoring system which checks the availability of your
|
||||
network resources, notifies users of outages and generates performance data for reporting.
|
||||
|
||||
Scalable and extensible, Icinga 2 can monitor complex, large environments across
|
||||
multiple locations.
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@ First of all you will have to install Icinga 2. The preferred way of doing this
|
|||
is to use the official Debian or RPM package repositories depending on which
|
||||
operating system and distribution you are running.
|
||||
|
||||
Distribution |Repository URL
|
||||
Distribution | Repository URL
|
||||
------------------------|---------------------------
|
||||
Debian |http://packages.icinga.org/debian/
|
||||
Ubuntu |http://packages.icinga.org/ubuntu/
|
||||
RHEL/CentOS 5 |http://packages.icinga.org/epel/5/release/
|
||||
RHEL/CentOS 6 |http://packages.icinga.org/epel/6/release/
|
||||
OpenSUSE 12.3 |http://packages.icinga.org/openSUSE/12.3/release/
|
||||
SLES 11 SP3 |http://packages.icinga.org/SUSE/sles11-sp3/release/
|
||||
Debian | http://packages.icinga.org/debian/
|
||||
Ubuntu | http://packages.icinga.org/ubuntu/
|
||||
RHEL/CentOS 5 | http://packages.icinga.org/epel/5/release/
|
||||
RHEL/CentOS 6 | http://packages.icinga.org/epel/6/release/
|
||||
OpenSUSE 12.3 | http://packages.icinga.org/openSUSE/12.3/release/
|
||||
SLES 11 SP3 | http://packages.icinga.org/SUSE/sles11-sp3/release/
|
||||
|
||||
Packages for distributions other than the ones listed above may also be
|
||||
available. Please check http://packages.icinga.org/ to see if packages
|
||||
|
@ -29,8 +29,7 @@ to install the `icinga2` package.
|
|||
> **Note**
|
||||
>
|
||||
> On RHEL/CentOS and SLES you will need to use `chkconfig` to enable the
|
||||
`icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2
|
||||
start`.
|
||||
> `icinga2` service. You can manually start Icinga 2 using `/etc/init.d/icinga2 start`.
|
||||
|
||||
Some parts of Icinga 2's functionality are available as separate packages:
|
||||
|
||||
|
@ -114,7 +113,7 @@ The `conf.d/macros.conf` file can be used to define global macros:
|
|||
/**
|
||||
* Global macros
|
||||
*/
|
||||
set IcingaMacros = {
|
||||
const IcingaMacros = {
|
||||
plugindir = "/usr/local/icinga/libexec"
|
||||
}
|
||||
|
||||
|
@ -137,6 +136,15 @@ The `conf.d/localhost.conf` file contains our first host definition:
|
|||
macros.address6 = "::1"
|
||||
}
|
||||
|
||||
This defines the host `localhost`. The `import` keyword is used to import
|
||||
the `linux-server` template which takes care of setting up the `ping4` and
|
||||
`ping6` services for the host as well as adding the host to the `linux-servers`
|
||||
host group.
|
||||
|
||||
The `macros` attribute can be used to define macros that are available for all
|
||||
services which belong to this host. Most of the templates in the Icinga Template
|
||||
Library require an `address` macro.
|
||||
|
||||
apply Service "icinga" {
|
||||
import "generic-service",
|
||||
|
||||
|
@ -199,13 +207,9 @@ The `conf.d/localhost.conf` file contains our first host definition:
|
|||
assign where host.name == "localhost"
|
||||
}
|
||||
|
||||
This defines a host named "localhost" which has a couple of services. Services
|
||||
may import one or more service templates.
|
||||
The `apply` keyword can be used to dynamically create services for all hosts based
|
||||
on rules.
|
||||
|
||||
The command objects `ping4`, `ping6`, `http_ip`, `ssh`, `load`, `processes`, `users`
|
||||
The command objects `http_ip`, `ssh`, `load`, `processes`, `users`
|
||||
and `disk` are all provided by the Icinga Template Library (short ITL) which
|
||||
we enabled earlier by including the `itl/itl.conf` configuration file.
|
||||
|
||||
The `macros` attribute can be used to define macros that are available for all
|
||||
services which belong to this host. Most of the templates in the Icinga Template
|
||||
Library require an `address` macro.
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
## <a id="setting-up-check-plugins"></a> Setting up Check Plugins
|
||||
|
||||
On its own Icinga 2 does not know how to check external services. The
|
||||
[Monitoring Plugins Project](https://www.monitoring-plugins.org/) (former
|
||||
Nagios Plugins) provides an extensive set of plugins which can be used by
|
||||
Icinga 2 to check whether services are working properly.
|
||||
[Monitoring Plugins Project](https://www.monitoring-plugins.org/) provides
|
||||
an extensive set of plugins which can be used with Icinga 2 to check whether
|
||||
services are working properly.
|
||||
|
||||
The recommended way of installing these standard plugins is to use your
|
||||
distribution's package manager.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The `Nagios Plugins` project was renamed to `Monitoring Plugins` project
|
||||
> in Jan 2014. Therefore package names may still reflect the old name.
|
||||
> The `Nagios Plugins` project was renamed to `Monitoring Plugins`
|
||||
> in January 2014. At the time of this writing the packages are still
|
||||
> using the old name.
|
||||
|
||||
For your convenience here is a list of package names for some of the more
|
||||
popular operating systems/distributions:
|
||||
|
@ -27,29 +28,41 @@ Depending on which directory your plugins are installed into you may need to
|
|||
update the `plugindir` macro in your Icinga 2 configuration. This macro is used
|
||||
by the service templates contained in the Icinga Template Library to determine
|
||||
where to find the plugin binaries.
|
||||
Alternatively you can create a symbolic link pointing to the installation path
|
||||
of the plugins.
|
||||
|
||||
### <a id="integrate-additional-plugins"></a> Integrate Additional Plugins
|
||||
|
||||
You may require a custom check plugin not provided by the official Nagios plugins.
|
||||
All existing Nagios or Icinga 1.x plugins found on public community websites
|
||||
will work with Icinga 2 as well.
|
||||
For some services you may need additional check plugins which are not provided
|
||||
by the official Monitoring Plugins project.
|
||||
|
||||
All existing Nagios or Icinga 1.x plugins should work with Icinga 2. Here's a
|
||||
list of popular community sites which host check plugins:
|
||||
|
||||
* [MonitoringExchange](https://www.monitoringexchange.org)
|
||||
* [Icinga Wiki](https://wiki.icinga.org)
|
||||
|
||||
Once you have downloaded the plugin copy it into the directory defined by the global
|
||||
`IcingaMacro` `$plugindir$` and make sure that the user the Icinga daemon is running as
|
||||
can execute the the plugin binary. Plugins should support the `--help` parameter
|
||||
providing details how they have to be called in your command definition later on.
|
||||
The recommended way of setting up these plugins is to copy them to a common directory
|
||||
and creating an extra global macro, e.g. `customplugindir` in your `macros.conf`
|
||||
configuration file:
|
||||
|
||||
# cp check_snmp_int.pl /usr/local/icinga/libexec/
|
||||
# chmod +x /usr/local/icinga/libexec/check_snmp_int.pl
|
||||
|
||||
# /usr/local/icinga/libexec/check_snmp_int.pl --help
|
||||
# cp check_snmp_int.pl /opt/plugins
|
||||
# chmod +x /opt/plugins/check_snmp_int.pl
|
||||
|
||||
# cat /etc/icinga2/conf/macros.conf
|
||||
/**
|
||||
* Global macros
|
||||
*/
|
||||
const IcingaMacros = {
|
||||
plugindir = "/usr/lib/nagios/plugins",
|
||||
customplugindir = "/opt/monitoring"
|
||||
}
|
||||
|
||||
Prior to using the check plugin with Icinga 2 you should ensure that it is working properly
|
||||
by trying to run it on the console using whichever user Icinga 2 is running as:
|
||||
|
||||
# su - icinga -s /bin/bash
|
||||
$ /opt/plugins/check_snmp_int.pl --help
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> You may require additional libraries for scripts. Please consult the installation
|
||||
> You may require additional libraries for some plugins. Please consult the installation
|
||||
> documentation and/or README for their installation requirements.
|
||||
|
|
|
@ -2,26 +2,19 @@
|
|||
|
||||
Icinga 2 supports three different types of logging:
|
||||
|
||||
* File logging (local Icinga 2 log file)
|
||||
* Syslog facility logging (system's syslog application)
|
||||
* File logging
|
||||
* Syslog (on *NIX-based operating systems)
|
||||
* Console logging (`STDOUT` on tty)
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> You can define multiple logging objects at once.
|
||||
You can enable additional loggers using the `icinga2-enable-feature`
|
||||
and `icinga2-disable-feature` commands to configure loggers:
|
||||
|
||||
The most common scenario will be logging Icinga 2's output to
|
||||
syslog with severity `information`.
|
||||
|
||||
object SyslogLogger "syslog" {
|
||||
severity = "information"
|
||||
}
|
||||
|
||||
For debugging purposes you can install a `FileLogger` object
|
||||
and forward the `debug` severity into an Icinga 2 debug file.
|
||||
|
||||
object FileLogger "debug-file" {
|
||||
severity = "debug",
|
||||
path = "/var/log/icinga2/debug.log"
|
||||
}
|
||||
Feature | Description
|
||||
---------|------------
|
||||
debuglog | Debug log (path: `/var/log/icinga2/debug.log`, severity: `debug` or higher)
|
||||
mainlog | Main log (path: `/var/log/icinga2/icinga2.log`, severity: `information` or higher)
|
||||
syslog | Syslog (severity: `warning` or higher)
|
||||
|
||||
By default file the `mainlog` feature is enabled. When running Icinga 2
|
||||
on a terminal log messages with severity `information` or higher are
|
||||
written to the console.
|
||||
|
|
|
@ -66,15 +66,15 @@ Example:
|
|||
Certain characters need to be escaped. The following escape sequences
|
||||
are supported:
|
||||
|
||||
Character |Escape sequence
|
||||
------------------------------------|------------------------------------
|
||||
" |\\"
|
||||
\\ |\\\\
|
||||
\<TAB\> |\\t
|
||||
\<CARRIAGE-RETURN\> |\\r
|
||||
\<LINE-FEED\> |\\n
|
||||
\<BEL\> |\\b
|
||||
\<FORM-FEED\> |\\f
|
||||
Character | Escape sequence
|
||||
--------------------------|------------------------------------
|
||||
" | \\"
|
||||
\\ | \\\\
|
||||
<TAB> | \\t
|
||||
<CARRIAGE-RETURN> | \\r
|
||||
<LINE-FEED> | \\n
|
||||
<BEL> | \\b
|
||||
<FORM-FEED> | \\f
|
||||
|
||||
In addition to these pre-defined escape sequences you can specify
|
||||
arbitrary ASCII characters using the backslash character (\\) followed
|
||||
|
@ -154,7 +154,8 @@ The following operators are supported in expressions:
|
|||
|
||||
Operator | Examples (Result) | Description
|
||||
---------|-----------------------------------------------|--------------------------------
|
||||
!, ~ | ~true (false) | Bitwise negation of the operand
|
||||
! | !"Hello" (false), !false (true) | Logical negation of the operand
|
||||
~ | ~true (false) | Bitwise negation of the operand
|
||||
+ | 1 + 3 (4), "hello " + "world" ("hello world") | Adds two numbers; concatenates strings
|
||||
- | 3 - 1 (2) | Subtracts two numbers
|
||||
* | 5m * 10 (3000) | Multiplies two numbers
|
||||
|
@ -295,6 +296,12 @@ The indexer syntax provides a convenient way to set dictionary elements.
|
|||
|
||||
Example:
|
||||
|
||||
{
|
||||
hello.key = "world"
|
||||
}
|
||||
|
||||
Example (alternative syntax):
|
||||
|
||||
{
|
||||
hello["key"] = "world"
|
||||
}
|
||||
|
@ -307,80 +314,55 @@ This is equivalent to writing:
|
|||
}
|
||||
}
|
||||
|
||||
### <a id="object-inheritance"></a> Object Inheritance
|
||||
### <a id="template-imports"></a> Template Imports
|
||||
|
||||
Objects can inherit attributes from other objects.
|
||||
Objects can import attributes from other objects.
|
||||
|
||||
Example:
|
||||
|
||||
template Host "default-host" {
|
||||
macros["color"] = "red"
|
||||
macros.color = "red"
|
||||
}
|
||||
|
||||
template Host "test-host" {
|
||||
import "default-host",
|
||||
|
||||
macros["color"] = "blue"
|
||||
macros.color = "blue"
|
||||
}
|
||||
|
||||
object Host "localhost" {
|
||||
import "test-host",
|
||||
|
||||
macros["address"] = "127.0.0.1",
|
||||
macros["address6"] = "::1"
|
||||
macros.address = "127.0.0.1",
|
||||
macros.address6 = "::1"
|
||||
}
|
||||
|
||||
The `default-host` and `test-host` objects are marked as templates
|
||||
using the `template` keyword. Unlike ordinary objects templates are not
|
||||
instantiated at run-time. Parent objects do not necessarily have to be
|
||||
templates though in general they are.
|
||||
templates, however in general they are.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The final macros dictionary contains all three macros and the macro
|
||||
> `color` has the value `"blue"`.
|
||||
> The macros dictionary for the `localhost` object contains all three
|
||||
> macros and the macro `color` has the value `"blue"`.
|
||||
|
||||
Parent objects are resolved in the order they're specified using the
|
||||
`import` keyword.
|
||||
|
||||
### <a id="disable-override-objects-attributes"></a> Disable/Override Objects and Attributes
|
||||
|
||||
Object attributes can be overridden by defining the additional changed attribute
|
||||
directly on the object. Use the `+=` operator for the inline services dictionary.
|
||||
|
||||
services["overridden-custom-attr"] += {
|
||||
custom = {
|
||||
notes = "disabled all custom attr"
|
||||
}
|
||||
}
|
||||
|
||||
If you don't require an attribute inherited from templates, you can simply
|
||||
override its value by setting it explicitely to `null`.
|
||||
|
||||
services["no-custom-attr"] += {
|
||||
custom = null
|
||||
}
|
||||
|
||||
The same method applies for disabling services defined in the inline `services`
|
||||
dictionary by explicitly overriding their value with `null`.
|
||||
|
||||
services["ping6"] = null
|
||||
|
||||
### <a id="constants"></a> Constants
|
||||
|
||||
Global constants can be set using the `const` keyword:
|
||||
|
||||
const VarName = "some value"
|
||||
|
||||
The value can be a string, number, array, or a dictionary.
|
||||
|
||||
Once defined a constant can be access from any file. Constants cannot be changed
|
||||
once they are set.
|
||||
|
||||
### <a id="apply"></a> Apply
|
||||
|
||||
The `apply` keyword can be used to associate a template with another group of
|
||||
objects. The exact effect of this association depends on the object type.
|
||||
The `apply` keyword can be used to create new objects which are associated with
|
||||
another group of objects.
|
||||
|
||||
apply Service "ping" {
|
||||
import "generic-service",
|
||||
|
@ -390,19 +372,43 @@ objects. The exact effect of this association depends on the object type.
|
|||
assign where host.name == "localhost"
|
||||
}
|
||||
|
||||
In this example the `assign where` condition is an expression which is
|
||||
evaluated for all objects of type Host and a new service with name "ping"
|
||||
In this example the `assign where` condition is a boolean expression which is
|
||||
evaluated for all objects of type `Host` and a new service with name "ping"
|
||||
is created for each matching host.
|
||||
|
||||
Depending on the object type used in the `apply` expression additional local
|
||||
variables may be available for use in the `where` condition:
|
||||
|
||||
Type |Variables
|
||||
-----------------|----------------
|
||||
Dependency |host, service
|
||||
Notification |host, service
|
||||
Service |host
|
||||
ScheduledDowntime|host, service
|
||||
Source Type | Target Type | Variables
|
||||
-----------------|-------------|--------------
|
||||
Service | Host | host
|
||||
Dependency | Service | host, service
|
||||
Notification | Service | host, service
|
||||
ScheduledDowntime| Service | host, service
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Any valid config attribute can be accessed using the `host` and `service`
|
||||
> variables. For example, `host.macros.address` would return the host's
|
||||
> "address" macro - or null if it doesn't have that macro.
|
||||
|
||||
### <a id="boolean-values"></a> Boolean Values
|
||||
|
||||
The `assign where` and `ignore where` statements, the unary `!`, `&&` and `||`
|
||||
operators as well as the `bool()` function convert their arguments to a
|
||||
boolean value based on the following rules:
|
||||
|
||||
Description | Example Value | Boolean Value
|
||||
---------------------|-------------------|--------------
|
||||
Empty value | null | false
|
||||
Zero | 0 | false
|
||||
Non-zero integer | -23945 | true
|
||||
Empty string | "" | false
|
||||
Non-empty string | "Hello" | true
|
||||
Empty array | [] | false
|
||||
Non-empty array | [ "Hello" ] | true
|
||||
Empty dictionary | {} | false
|
||||
Non-empty dictionary | { key = "value" } | true
|
||||
|
||||
### <a id="comments"></a> Comments
|
||||
|
||||
|
@ -440,7 +446,7 @@ C/C++ compiler:
|
|||
|
||||
Note the use of angle brackets instead of double quotes. This causes the
|
||||
config compiler to search the include search paths for the specified
|
||||
file. By default $PREFIX/icinga2 is included in the list of search
|
||||
file. By default $PREFIX/share/icinga2 is included in the list of search
|
||||
paths. Additional include search paths can be added using
|
||||
[command-line options](#cmdline).
|
||||
|
||||
|
@ -466,7 +472,7 @@ When no pattern is specified the default pattern "*.conf" is used.
|
|||
|
||||
The `library` directive can be used to manually load additional
|
||||
libraries. Libraries can be used to provide additional object types and
|
||||
methods.
|
||||
functions.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -474,8 +480,8 @@ Example:
|
|||
|
||||
> **Note**
|
||||
>
|
||||
> The `icinga` library is automatically loaded at startup. You don't need
|
||||
> to load it manually.
|
||||
> The `icinga` and `methods` libraries is automatically loaded at startup.
|
||||
> You don't need to load them manually.
|
||||
|
||||
<!--
|
||||
|
||||
|
@ -519,7 +525,8 @@ The Pizza definition provides the following validation rules:
|
|||
- If they're a dictionary they may contain attributes `quantity` (of
|
||||
type number) and `name` (of type string).
|
||||
|
||||
- The script function `ValidateIngredients` is run to perform further
|
||||
- The s
|
||||
- cript function `ValidateIngredients` is run to perform further
|
||||
validation of the ingredients dictionary.
|
||||
|
||||
- Pizza objects may contain attribute matching the pattern
|
||||
|
|
|
@ -4,7 +4,7 @@ Icinga 2 provides a number of special global constants. Some of them can be over
|
|||
|
||||
Variable |Description
|
||||
--------------------------|-------------------
|
||||
IcingaPrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to /usr/local
|
||||
IcingaPrefixDir |**Read-only.** Contains the installation prefix that was specified with cmake -DCMAKE_INSTALL_PREFIX. Defaults to "/usr/local".
|
||||
IcingaSysconfDir |**Read-only.** Contains the path of the sysconf directory. Defaults to IcingaPrefixDir + "/etc".
|
||||
IcingaLocalStateDir |**Read-only.** Contains the path of the local state directory. Defaults to IcingaPrefixDir + "/var".
|
||||
IcingaPkgDataDir |**Read-only.** Contains the path of the package data directory. Defaults to IcingaPrefixDir + "/share/icinga2".
|
||||
|
|
|
@ -17,10 +17,6 @@ Example:
|
|||
|
||||
groups = [ "all-hosts" ],
|
||||
|
||||
services["ping"] = {
|
||||
templates = [ "ping" ]
|
||||
},
|
||||
|
||||
check = "ping"
|
||||
}
|
||||
|
||||
|
@ -334,7 +330,7 @@ Attributes:
|
|||
Name |Description
|
||||
----------------|----------------
|
||||
display_name |**Optional.** A short description of the time period.
|
||||
methods |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should just inherit from the "legacy-timeperiod" template to take care of this setting.
|
||||
methods |**Required.** The "update" script method takes care of updating the internal representation of the time period. In virtually all cases you should import the "legacy-timeperiod" template to take care of this setting.
|
||||
ranges |**Required.** A dictionary containing information which days and durations apply to this timeperiod.
|
||||
|
||||
The `/etc/icinga2/conf.d/timeperiods.conf` file is usually used to define
|
||||
|
@ -435,7 +431,7 @@ Attributes:
|
|||
|
||||
Name |Description
|
||||
----------------|----------------
|
||||
methods |**Required.** The "execute" script method takes care of executing the check. In virtually all cases you should just inherit from the "plugin-check-command" template to take care of this setting.
|
||||
methods |**Required.** The "execute" script method takes care of executing the check. In virtually all cases you should import the "plugin-check-command" template to take care of this setting.
|
||||
command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command.
|
||||
export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command.
|
||||
escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
|
||||
|
@ -473,7 +469,7 @@ Attributes:
|
|||
|
||||
Name |Description
|
||||
----------------|----------------
|
||||
methods |**Required.** The "execute" script method takes care of executing the notification. In virtually all cases you should just inherit from the "plugin-notification-command" template to take care of this setting.
|
||||
methods |**Required.** The "execute" script method takes care of executing the notification. In virtually all cases you should import the "plugin-notification-command" template to take care of this setting.
|
||||
command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command.
|
||||
export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command.
|
||||
escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
|
||||
|
@ -501,7 +497,7 @@ Attributes:
|
|||
|
||||
Name |Description
|
||||
----------------|----------------
|
||||
methods |**Required.** The "execute" script method takes care of executing the event handler. In virtually all cases you should just inherit from the "plugin-event-command" template to take care of this setting.
|
||||
methods |**Required.** The "execute" script method takes care of executing the event handler. In virtually all cases you should import the "plugin-event-command" template to take care of this setting.
|
||||
command |**Required.** The command. This can either be an array of individual command arguments. Alternatively a string can be specified in which case the shell interpreter (usually /bin/sh) takes care of parsing the command.
|
||||
export_macros |**Optional.** A list of macros which should be exported as environment variables prior to executing the command.
|
||||
escape_macros |**Optional.** A list of macros which should be shell-escaped in the command.
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
### <a id="best-practice-config-structure"></a> Configuration File and Directory Structure
|
||||
|
||||
Icinga 2 does not care how you name your files and/or directories as long as
|
||||
you'll include them accordingly in the [icinga2.conf](#icinga2-conf) file.
|
||||
you include them in the [icinga2.conf](#icinga2-conf) file.
|
||||
|
||||
By default, the `conf.d` directory is included recursively looking for files
|
||||
which match the pattern `*.conf`.
|
||||
|
||||
By default, `conf.d` is included recursively looking for `*.conf` file endings.
|
||||
If you're putting/generating your configuration structure in there, you do not
|
||||
need to touch the [icinga2.conf](#icinga2-conf) file. This becomes useful with
|
||||
external addons not having write permissions to this file such as LConf.
|
||||
|
|
Loading…
Reference in New Issue