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