diff --git a/doc/02-getting-started.md b/doc/02-getting-started.md
index 4f4af739c..30cc38f82 100644
--- a/doc/02-getting-started.md
+++ b/doc/02-getting-started.md
@@ -175,11 +175,11 @@ By default Icinga 2 uses the following files and directories:
/usr/lib\*/icinga2 | Libraries and the Icinga 2 binary (use `find /usr -type f -name icinga2` to locate the binary path).
/usr/share/doc/icinga2 | Documentation files that come with Icinga 2.
/usr/share/icinga2/include | The Icinga Template Library and plugin command configuration.
+ /var/lib/icinga2 | Icinga 2 state file, cluster log, master CA, node certificates and configuration files (cluster, api).
/var/run/icinga2 | PID file.
/var/run/icinga2/cmd | Command pipe and Livestatus socket.
/var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files
/var/spool/icinga2 | Used for performance data spool files.
- /var/lib/icinga2 | Icinga 2 state file, cluster log, local CA and configuration files (cluster, api).
/var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature.
FreeBSD uses slightly different paths:
@@ -194,11 +194,11 @@ By default Icinga 2 uses the following files and directories:
/usr/local/lib/icinga2 | Libraries and the Icinga 2 binary.
/usr/local/share/doc/icinga2 | Documentation files that come with Icinga 2.
/usr/local/share/icinga2/include | The Icinga Template Library and plugin command configuration.
+ /var/lib/icinga2 | Icinga 2 state file, cluster log, master CA, node certificates and configuration files (cluster, api).
/var/run/icinga2 | PID file.
/var/run/icinga2/cmd | Command pipe and Livestatus socket.
/var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files
/var/spool/icinga2 | Used for performance data spool files.
- /var/lib/icinga2 | Icinga 2 state file, cluster log, local CA and configuration files (cluster, api).
/var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature.
## Setting up Check Plugins
@@ -877,5 +877,6 @@ popular addons is available in the
Ensure to include the following in your backups:
* Configuration files in `/etc/icinga2`
-* Runtime files in `/var/lib/icinga2` (the master's CA is stored here as well)
+* Certificate files in `/var/lib/icinga2/ca` (Master CA key pair) and `/var/lib/icinga2/certs` (node certificates)
+* Runtime files in `/var/lib/icinga2`
* Optional: IDO database backup
diff --git a/doc/06-distributed-monitoring.md b/doc/06-distributed-monitoring.md
index e0a48eedb..13c415852 100644
--- a/doc/06-distributed-monitoring.md
+++ b/doc/06-distributed-monitoring.md
@@ -553,6 +553,11 @@ The setup wizard will ensure that the following steps are taken:
You can verify that the certificate files are stored in the `/var/lib/icinga2/certs` directory.
+> **Note**
+>
+> The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths)
+> for more details.
+
> **Note**
>
> If the client is not directly connected to the certificate signing master,
@@ -2358,6 +2363,11 @@ Sign the CSR with the previously created CA:
[root@icinga2-master1.localdomain /root]# icinga2 pki sign-csr --csr icinga2-master1.localdomain.csr --cert icinga2-master1.localdomain
+> **Note**
+>
+> The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths)
+> for more details.
+
Copy the host's certificate files and the public CA certificate to `/var/lib/icinga2/certs`:
[root@icinga2-master1.localdomain /root]# mkdir -p /var/lib/icinga2/certs
@@ -2444,7 +2454,12 @@ host/port you can specify it like this:
#### Node Setup with Satellites/Clients
-Make sure that the `/var/lib/icinga2/certs` exists and is owned by the `icinga`
+> **Note**
+>
+> The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths)
+> for more details.
+
+Make sure that the `/var/lib/icinga2/certs` directory exists and is owned by the `icinga`
user (or the user Icinga 2 is running as).
[root@icinga2-client1.localdomain /]# mkdir -p /var/lib/icinga2/certs
@@ -2499,7 +2514,7 @@ Pass the following details to the `node setup` CLI command:
Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)).
Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)).
-Example:
+Example for Icinga 2 v2.8:
[root@icinga2-client1.localdomain /]# icinga2 node setup --ticket ead2d570e18c78abf285d6b85524970a0f69c22d \
--cn icinga2-client1.localdomain \
diff --git a/doc/09-object-types.md b/doc/09-object-types.md
index 4a94f2534..036534344 100644
--- a/doc/09-object-types.md
+++ b/doc/09-object-types.md
@@ -41,9 +41,8 @@ Example:
```
object ApiListener "api" {
- cert_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"
- key_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"
- ca_path = LocalStateDir + "/lib/icinga2/certs/ca.crt"
+ accept_commands = true
+ accept_config = true
ticket_salt = TicketSalt
}
@@ -53,9 +52,9 @@ Configuration Attributes:
Name | Type | Description
--------------------------------------|-----------------------|----------------------------------
- cert\_path | String | **Required.** Path to the public key.
- key\_path | String | **Required.** Path to the private key.
- ca\_path | String | **Required.** Path to the CA certificate file.
+ cert\_path | String | **Deprecated.** Path to the public key.
+ key\_path | String | **Deprecated.** Path to the private key.
+ ca\_path | String | **Deprecated.** Path to the CA certificate file.
ticket\_salt | String | **Optional.** Private key for [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). **Required** for a signing master instance.
crl\_path | String | **Optional.** Path to the CRL file.
bind\_host | String | **Optional.** The IP address the api listener should be bound to. Defaults to `0.0.0.0`.
@@ -69,6 +68,20 @@ Configuration Attributes:
access\_control\_allow\_headers | String | **Optional.** Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request. Defaults to `Authorization`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Headers)
access\_control\_allow\_methods | String | **Optional.** Used in response to a preflight request to indicate which HTTP methods can be used when making the actual request. Defaults to `GET, POST, PUT, DELETE`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Methods)
+The ApiListener type expects its certificate files to be in the following locations:
+
+ Type | Location
+ ---------------------|-------------------------------------
+ Private key | `LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"`
+ Certificate file | `LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"`
+ CA certificate file | `LocalStateDir + "/lib/icinga2/certs/ca.crt"`
+
+If the deprecated attributes `cert_path`, `key_path` and/or `ca_path` are specified Icinga 2
+copies those files to the new location in `LocalStateDir + "/lib/icinga2/certs"` unless the
+file(s) there are newer.
+
+Please check the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) for more details.
+
## ApiUser
ApiUser objects are used for authentication against the [Icinga 2 API](12-icinga2-api.md#icinga2-api-authentication).
diff --git a/doc/16-upgrading-icinga-2.md b/doc/16-upgrading-icinga-2.md
index c5c85402d..99962280a 100644
--- a/doc/16-upgrading-icinga-2.md
+++ b/doc/16-upgrading-icinga-2.md
@@ -10,19 +10,103 @@ are scheme updates for the IDO database.
The default certificate path was changed from `/etc/icinga2/pki` to
`/var/lib/icinga2/certs`.
+ Old Path | New Path
+ ---------------------------------------------------|---------------------------------------------------
+ `/etc/icinga2/pki/icinga2-client1.localdomain.crt` | `/var/lib/icinga2/certs/icinga2-client1.localdomain.crt`
+ `/etc/icinga2/pki/icinga2-client1.localdomain.key` | `/var/lib/icinga2/certs/icinga2-client1.localdomain.key`
+ `/etc/icinga2/pki/ca.crt` | `/var/lib/icinga2/certs/ca.crt`
+
This applies to Windows clients in the same way: `%ProgramData%\etc\icinga2\pki`
-was moved to `%ProgramData%`\var\lib\icinga2\certs`.
+was moved to `%ProgramData%\var\lib\icinga2\certs`.
+
+ Old Path | New Path
+ ----------------------------------------------------------------|----------------------------------------------------------------
+ `%ProgramData%\etc\icinga2\pki\icinga2-client1.localdomain.crt` | `%ProgramData%\var\lib\icinga2\certs\icinga2-client1.localdomain.crt`
+ `%ProgramData%\etc\icinga2\pki\icinga2-client1.localdomain.key` | `%ProgramData%\var\lib\icinga2\certs\icinga2-client1.localdomain.key`
+ `%ProgramData%\etc\icinga2\pki\ca.crt` | `%ProgramData%\var\lib\icinga2\certs\ca.crt`
+
+
+> **Note**
+>
+> The default expected path for client certificates is `/var/lib/icinga2/certs/ + NodeName + {.crt,.key}`.
+> The `NodeName` constant is usually the FQDN and certificate common name (CN). Check the [conventions](06-distributed-monitoring.md#distributed-monitoring-conventions)
+> section inside the Distributed Monitoring chapter.
The [setup CLI commands](06-distributed-monitoring.md#distributed-monitoring-setup-master) and the
default [ApiListener configuration](06-distributed-monitoring.md#distributed-monitoring-apilistener)
have been adjusted to these paths too.
+The [ApiListener](09-object-types.md#objecttype-apilistener) object attributes `cert_path`, `key_path`
+and `ca_path` have been deprecated and removed from the example configuration.
+
+#### Migration Path
+
+> **Note**
+>
+> Icinga 2 automatically migrates the certificates to the new default location if they
+> are configured and detected in `/etc/icinga2/pki`.
+
+During startup, the migration kicks in and ensures to copy the certificates to the new
+location. This will also happen if someone updates the certificate files in `/etc/icinga2/pki`
+to ensure that the new certificate location always has the latest files.
+
+This has been implemented in the Icinga 2 binary to ensure it works on both Linux/Unix
+and the Windows platform.
+
+If you are not using the built-in CLI commands and setup wizards to deploy the client certificates,
+please ensure to update your deployment tools/scripts. This mainly affects
+
+* Puppet modules
+* Ansible playbooks
+* Chef cookbooks
+* Salt recipes
+* Custom scripts, e.g. Windows Powershell or self-made implementations
+
+In order to support a smooth migration between versions older than 2.8 and future releases,
+the built-in certificate migration path is planned to exist as long as the deprecated
+`ApiListener` object attributes exist.
+
+You are safe to use the existing configuration paths inside the `api` feature. If you plan your migration,
+look at the following example taken from the Director Linux deployment script for clients.
+
+* Ensure that the default certificate path is changed from `/etc/icinga2/pki` to `/var/lib/icinga2/certs`.
+
+```
+-ICINGA2_SSL_DIR="${ICINGA2_CONF_DIR}/pki"
++ICINGA2_SSL_DIR="${ICINGA2_STATE_DIR}/lib/icinga2/certs"
+```
+
+* Remove the ApiListener configuration attributes.
+
+```
+object ApiListener "api" {
+- cert_path = SysconfDir + "/icinga2/pki/${ICINGA2_NODENAME}.crt"
+- key_path = SysconfDir + "/icinga2/pki/${ICINGA2_NODENAME}.key"
+- ca_path = SysconfDir + "/icinga2/pki/ca.crt"
+ accept_commands = true
+ accept_config = true
+}
+```
+
+Test the script with a fresh client installation before putting it into production.
+
+> **Tip**
+>
+> Please support module and script developers in their migration. If you find
+> any project which would require these changes, create an issue or a patchset in a PR
+> and help them out. Thanks in advance!
+
+
### Removed Bottom Up Client Mode
This client mode was deprecated in 2.6 and was removed in 2.8.
The node CLI command does not provide `list` or `update-config` anymore.
+> **Note**
+>
+> The old migration guide can be found on [GitHub](https://github.com/Icinga/icinga2/blob/v2.7.0/doc/06-distributed-monitoring.md#bottom-up-migration-to-top-down-).
+
The clients don't need to have a local `conf.d` directory included.
The setup wizards for Linux and Windows attempt to disable this by default.
@@ -31,6 +115,7 @@ You are advised to [migrate](https://github.com/Icinga/icinga2/issues/4798)
any existing configuration to the "top down" mode with the help of the
Icinga Director or config management tools such as Puppet, Ansible, etc.
+
### Removed Classic UI Config Package
The config meta package `classicui-config` and the configuration files
diff --git a/etc/icinga2/features-available/api.conf b/etc/icinga2/features-available/api.conf
index c24b09a4d..b072a4406 100644
--- a/etc/icinga2/features-available/api.conf
+++ b/etc/icinga2/features-available/api.conf
@@ -3,9 +3,8 @@
*/
object ApiListener "api" {
- cert_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"
- key_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"
- ca_path = LocalStateDir + "/lib/icinga2/certs/ca.crt"
+ //accept_config = false
+ //accept_commands = false
ticket_salt = TicketSalt
}
diff --git a/lib/base/function.ti b/lib/base/function.ti
index b42e90ee8..be50525c5 100644
--- a/lib/base/function.ti
+++ b/lib/base/function.ti
@@ -28,7 +28,7 @@ abstract class Function
{
[config] String "name";
[config] bool side_effect_free;
- [config] bool deprecated;
+ [config] bool "deprecated";
[config] Array::Ptr arguments;
};
diff --git a/lib/base/type.hpp b/lib/base/type.hpp
index fdc40c21e..52aa753a5 100644
--- a/lib/base/type.hpp
+++ b/lib/base/type.hpp
@@ -39,7 +39,8 @@ enum FieldAttribute
FARequired = 256,
FANavigation = 512,
FANoUserModify = 1024,
- FANoUserView = 2048
+ FANoUserView = 2048,
+ FADeprecated = 4096,
};
class Type;
diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp
index 6cb2ed107..836393b03 100644
--- a/lib/base/utility.cpp
+++ b/lib/base/utility.cpp
@@ -816,6 +816,10 @@ void Utility::CollectPaths(const String& path, std::vector& paths)
paths.push_back(path);
}
+/*
+ * Copies a source file to a target location.
+ * Caller must ensure that the target's base directory exists and is writable.
+ */
void Utility::CopyFile(const String& source, const String& target)
{
std::ifstream ifs(source.CStr(), std::ios::binary);
diff --git a/lib/cli/nodesetupcommand.cpp b/lib/cli/nodesetupcommand.cpp
index 302dccae8..c452c2267 100644
--- a/lib/cli/nodesetupcommand.cpp
+++ b/lib/cli/nodesetupcommand.cpp
@@ -173,10 +173,7 @@ int NodeSetupCommand::SetupMaster(const boost::program_options::variables_map& v
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
<< " */\n"
- << "object ApiListener \"api\" {\n"
- << " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
- << " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
- << " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n";
+ << "object ApiListener \"api\" {\n";
if (vm.count("listen")) {
std::vector tokens;
@@ -378,10 +375,7 @@ int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm,
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
<< " */\n"
- << "object ApiListener \"api\" {\n"
- << " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
- << " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
- << " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n";
+ << "object ApiListener \"api\" {\n";
if (vm.count("listen")) {
std::vector tokens;
diff --git a/lib/cli/nodewizardcommand.cpp b/lib/cli/nodewizardcommand.cpp
index 0cf4636ff..c3c003204 100644
--- a/lib/cli/nodewizardcommand.cpp
+++ b/lib/cli/nodewizardcommand.cpp
@@ -472,10 +472,6 @@ wizard_ticket:
<< " * The API listener is used for distributed monitoring setups.\n"
<< " */\n"
<< "object ApiListener \"api\" {\n"
- << " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
- << " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
- << " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n"
- << "\n"
<< " accept_config = " << acceptConfig << "\n"
<< " accept_commands = " << acceptCommands << "\n";
@@ -629,10 +625,7 @@ int NodeWizardCommand::MasterSetup(void) const
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
<< " */\n"
- << "object ApiListener \"api\" {\n"
- << " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
- << " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
- << " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n";
+ << "object ApiListener \"api\" {\n";
if (!bindHost.IsEmpty())
fp << " bind_host = \"" << bindHost << "\"\n";
diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp
index 45605dd61..86cc79759 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -75,6 +75,34 @@ String ApiListener::GetCertificateRequestsDir(void)
return Application::GetLocalStateDir() + "/lib/icinga2/certificate-requests/";
}
+String ApiListener::GetDefaultCertPath(void)
+{
+ return GetCertsDir() + "/" + ScriptGlobal::Get("NodeName") + ".crt";
+}
+
+String ApiListener::GetDefaultKeyPath(void)
+{
+ return GetCertsDir() + "/" + ScriptGlobal::Get("NodeName") + ".key";
+}
+
+String ApiListener::GetDefaultCaPath(void)
+{
+ return GetCertsDir() + "/ca.crt";
+}
+
+void ApiListener::CopyCertificateFile(const String& oldCertPath, const String& newCertPath)
+{
+ struct stat st1, st2;
+
+ if (!oldCertPath.IsEmpty() && stat(oldCertPath.CStr(), &st1) >= 0 && (stat(newCertPath.CStr(), &st2) < 0 || st1.st_mtime > st2.st_mtime)) {
+ Log(LogWarning, "ApiListener")
+ << "Copying '" << oldCertPath << "' certificate file to '" << newCertPath << "'";
+
+ Utility::MkDirP(Utility::DirName(newCertPath), 0700);
+ Utility::CopyFile(oldCertPath, newCertPath);
+ }
+}
+
void ApiListener::OnConfigLoaded(void)
{
if (m_Instance)
@@ -82,20 +110,37 @@ void ApiListener::OnConfigLoaded(void)
m_Instance = this;
+ String defaultCertPath = GetDefaultCertPath();
+ String defaultKeyPath = GetDefaultKeyPath();
+ String defaultCaPath = GetDefaultCaPath();
+
+ /* Migrate certificate location < 2.8 to the new default path. */
+ String oldCertPath = GetCertPath();
+ String oldKeyPath = GetKeyPath();
+ String oldCaPath = GetCaPath();
+
+ CopyCertificateFile(oldCertPath, defaultCertPath);
+ CopyCertificateFile(oldKeyPath, defaultKeyPath);
+ CopyCertificateFile(oldCaPath, defaultCaPath);
+
+ if (!oldCertPath.IsEmpty() && !oldKeyPath.IsEmpty() && !oldCaPath.IsEmpty()) {
+ Log(LogWarning, "ApiListener", "Please read the upgrading documentation for v2.8: https://www.icinga.com/docs/icinga2/latest/doc/16-upgrading-icinga-2/");
+ }
+
/* set up SSL context */
boost::shared_ptr cert;
try {
- cert = GetX509Certificate(GetCertPath());
+ cert = GetX509Certificate(defaultCertPath);
} catch (const std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate from cert path: '"
- + GetCertPath() + "'.", GetDebugInfo()));
+ + defaultCertPath + "'.", GetDebugInfo()));
}
try {
SetIdentity(GetCertificateCN(cert));
} catch (const std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate common name from cert path: '"
- + GetCertPath() + "'.", GetDebugInfo()));
+ + defaultCertPath + "'.", GetDebugInfo()));
}
Log(LogInformation, "ApiListener")
@@ -109,10 +154,10 @@ void ApiListener::UpdateSSLContext(void)
boost::shared_ptr context;
try {
- context = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath());
+ context = MakeSSLContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath());
} catch (const std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '"
- + GetCertPath() + "' key path: '" + GetKeyPath() + "' ca path: '" + GetCaPath() + "'.", GetDebugInfo()));
+ + GetDefaultCertPath() + "' key path: '" + GetDefaultKeyPath() + "' ca path: '" + GetDefaultCaPath() + "'.", GetDebugInfo()));
}
if (!GetCrlPath().IsEmpty()) {
@@ -420,7 +465,7 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri
identity = GetCertificateCN(cert);
} catch (const std::exception&) {
Log(LogCritical, "ApiListener")
- << "Cannot get certificate common name from cert path: '" << GetCertPath() << "'.";
+ << "Cannot get certificate common name from cert path: '" << GetDefaultCertPath() << "'.";
return;
}
diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp
index e4d244f35..1ce70316c 100644
--- a/lib/remote/apilistener.hpp
+++ b/lib/remote/apilistener.hpp
@@ -104,6 +104,10 @@ public:
static bool IsHACluster(void);
static String GetFromZoneName(const Zone::Ptr& fromZone);
+ static String GetDefaultCertPath(void);
+ static String GetDefaultKeyPath(void);
+ static String GetDefaultCaPath(void);
+
protected:
virtual void OnConfigLoaded(void) override;
virtual void OnAllConfigLoaded(void) override;
@@ -157,6 +161,8 @@ private:
static void LogGlobHandler(std::vector& files, const String& file);
void ReplayLog(const JsonRpcConnection::Ptr& client);
+ static void CopyCertificateFile(const String& oldCertPath, const String& newCertPath);
+
/* filesync */
static ConfigDirInformation LoadConfigDir(const String& dir);
static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config);
diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti
index 41ec97705..41f372992 100644
--- a/lib/remote/apilistener.ti
+++ b/lib/remote/apilistener.ti
@@ -28,9 +28,9 @@ namespace icinga
class ApiListener : ConfigObject
{
- [config, required] String cert_path;
- [config, required] String key_path;
- [config, required] String ca_path;
+ [config, deprecated] String cert_path;
+ [config, deprecated] String key_path;
+ [config, deprecated] String ca_path;
[config] String crl_path;
[config] String cipher_list {
default {{{ return "ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL"; }}}
diff --git a/lib/remote/jsonrpcconnection-pki.cpp b/lib/remote/jsonrpcconnection-pki.cpp
index 722239bfc..048d6c1c1 100644
--- a/lib/remote/jsonrpcconnection-pki.cpp
+++ b/lib/remote/jsonrpcconnection-pki.cpp
@@ -56,7 +56,7 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
cert = StringToCertificate(certText);
ApiListener::Ptr listener = ApiListener::GetInstance();
- boost::shared_ptr cacert = GetX509Certificate(listener->GetCaPath());
+ boost::shared_ptr cacert = GetX509Certificate(listener->GetDefaultCaPath());
String cn = GetCertificateCN(cert);
@@ -183,7 +183,7 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
* a certificate it wouldn't be able to use to connect to us anyway) */
if (!VerifyCertificate(cacert, newcert)) {
Log(LogWarning, "JsonRpcConnection")
- << "The CA in '" << listener->GetCaPath() << "' does not match the CA which Icinga uses "
+ << "The CA in '" << listener->GetDefaultCaPath() << "' does not match the CA which Icinga uses "
<< "for its own cluster connections. This is most likely a configuration problem.";
goto delayed_request;
}
@@ -285,7 +285,7 @@ Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionar
if (!listener)
return Empty;
- boost::shared_ptr oldCert = GetX509Certificate(listener->GetCertPath());
+ boost::shared_ptr oldCert = GetX509Certificate(listener->GetDefaultCertPath());
boost::shared_ptr newCert = StringToCertificate(cert);
String cn = GetCertificateCN(newCert);
@@ -328,7 +328,7 @@ Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionar
}
/* Update CA certificate. */
- String caPath = listener->GetCaPath();
+ String caPath = listener->GetDefaultCaPath();
Log(LogInformation, "JsonRpcConnection")
<< "Updating CA certificate in '" << caPath << "'.";
@@ -350,7 +350,7 @@ Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionar
}
/* Update signed certificate. */
- String certPath = listener->GetCertPath();
+ String certPath = listener->GetDefaultCertPath();
Log(LogInformation, "JsonRpcConnection")
<< "Updating client certificate for CN '" << cn << "' in '" << certPath << "'.";
diff --git a/lib/remote/typequeryhandler.cpp b/lib/remote/typequeryhandler.cpp
index cc2004470..73dde3678 100644
--- a/lib/remote/typequeryhandler.cpp
+++ b/lib/remote/typequeryhandler.cpp
@@ -149,6 +149,7 @@ bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& requ
attributeInfo->Set("navigation", static_cast(field.Attributes & FANavigation));
attributeInfo->Set("no_user_modify", static_cast(field.Attributes & FANoUserModify));
attributeInfo->Set("no_user_view", static_cast(field.Attributes & FANoUserView));
+ attributeInfo->Set("deprecated", static_cast(field.Attributes & FADeprecated));
}
}
diff --git a/tools/mkclass/class_lexer.ll b/tools/mkclass/class_lexer.ll
index 287ee9bd7..0b9195464 100644
--- a/tools/mkclass/class_lexer.ll
+++ b/tools/mkclass/class_lexer.ll
@@ -147,6 +147,7 @@ protected { yylval->num = FAGetProtected | FASetProtected; return T_FIELD_ATTR
no_storage { yylval->num = FANoStorage; return T_FIELD_ATTRIBUTE; }
no_user_modify { yylval->num = FANoUserModify; return T_FIELD_ATTRIBUTE; }
no_user_view { yylval->num = FANoUserView; return T_FIELD_ATTRIBUTE; }
+deprecated { yylval->num = FADeprecated; return T_FIELD_ATTRIBUTE; }
navigation { return T_NAVIGATION; }
validator { return T_VALIDATOR; }
required { return T_REQUIRED; }
diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp
index bff7b0290..eb44de809 100644
--- a/tools/mkclass/classcompiler.cpp
+++ b/tools/mkclass/classcompiler.cpp
@@ -510,6 +510,15 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
m_Impl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast(this), boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl;
}
+ if (field.Attributes & FADeprecated) {
+ if (field.Type.GetRealType().find("::Ptr") != std::string::npos)
+ m_Impl << "\t" << "if (" << argName << ")" << std::endl;
+ else
+ m_Impl << "\t" << "if (!" << argName << ".IsEmpty())" << std::endl;
+
+ m_Impl << "\t\t" << "Log(LogWarning, \"" << klass.Name << "\") << \"Attribute '" << field.Name << "' for object '\" << dynamic_cast(this)->GetName() << \"' of type '\" << dynamic_cast(this)->GetReflectionType()->GetName() << \"' is deprecated and should not be used.\";" << std::endl;
+ }
+
if (field.Type.ArrayRank > 0) {
m_Impl << "\t" << "if (avalue) {" << std::endl
<< "\t\t" << "ObjectLock olock(avalue);" << std::endl
diff --git a/tools/mkclass/classcompiler.hpp b/tools/mkclass/classcompiler.hpp
index df1a3660c..06bf100d3 100644
--- a/tools/mkclass/classcompiler.hpp
+++ b/tools/mkclass/classcompiler.hpp
@@ -72,7 +72,8 @@ enum FieldAttribute
FARequired = 256,
FANavigation = 512,
FANoUserModify = 1024,
- FANoUserView = 2048
+ FANoUserView = 2048,
+ FADeprecated = 4096
};
struct FieldType