1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "cli/nodewizardcommand.hpp"
21 #include "cli/nodeutility.hpp"
22 #include "cli/featureutility.hpp"
23 #include "cli/apisetuputility.hpp"
24 #include "remote/apilistener.hpp"
25 #include "remote/pkiutility.hpp"
26 #include "base/logger.hpp"
27 #include "base/console.hpp"
28 #include "base/application.hpp"
29 #include "base/tlsutility.hpp"
30 #include "base/scriptglobal.hpp"
31 #include "base/exception.hpp"
32 #include <boost/algorithm/string/join.hpp>
33 #include <boost/algorithm/string/replace.hpp>
34 #include <boost/algorithm/string/case_conv.hpp>
40 using namespace icinga;
41 namespace po = boost::program_options;
43 REGISTER_CLICOMMAND("node/wizard", NodeWizardCommand);
45 String NodeWizardCommand::GetDescription() const
47 return "Wizard for Icinga 2 node setup.";
50 String NodeWizardCommand::GetShortDescription() const
52 return "wizard for node setup";
55 ImpersonationLevel NodeWizardCommand::GetImpersonationLevel() const
57 return ImpersonateRoot;
60 int NodeWizardCommand::GetMaxArguments() const
65 void NodeWizardCommand::InitParameters(boost::program_options::options_description& visibleDesc,
66 boost::program_options::options_description& hiddenDesc) const
68 visibleDesc.add_options()
69 ("verbose", "increase log level");
73 * The entry point for the "node wizard" CLI command.
75 * @returns An exit status.
77 int NodeWizardCommand::Run(const boost::program_options::variables_map& vm,
78 const std::vector<std::string>& ap) const
80 if (!vm.count("verbose"))
81 Logger::SetConsoleLogSeverity(LogCritical);
84 * The wizard will get all information from the user,
85 * and then call all required functions.
88 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundBlue)
89 << "Welcome to the Icinga 2 Setup Wizard!\n"
91 << "We will guide you through all required configuration details.\n"
93 << ConsoleColorTag(Console_Normal);
95 /* 0. master or node setup?
97 * 2. Master information for autosigning
98 * 3. Trusted cert location
99 * 4. CN to use (defaults to FQDN)
101 * 6. New self signed certificate
102 * 7. Request signed certificate from master
103 * 8. copy key information to /var/lib/icinga2/certs
104 * 9. enable ApiListener feature
105 * 10. generate zones.conf with endpoints and zone objects
106 * 11. set NodeName = cn in constants.conf
107 * 12. disable conf.d directory?
108 * 13. reload icinga2, or tell the user to
112 /* master or satellite/client setup */
113 std::cout << ConsoleColorTag(Console_Bold)
114 << "Please specify if this is a satellite/client setup "
115 << "('n' installs a master setup)" << ConsoleColorTag(Console_Normal)
117 std::getline (std::cin, answer);
119 boost::algorithm::to_lower(answer);
121 String choice = answer;
127 if (choice.Contains("n"))
136 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
138 << ConsoleColorTag(Console_Normal);
140 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundRed)
141 << "Now restart your Icinga 2 daemon to finish the installation!\n"
142 << ConsoleColorTag(Console_Normal);
147 int NodeWizardCommand::ClientSetup() const
151 bool connectToParent = false;
153 std::cout << "Starting the Client/Satellite setup routine...\n\n";
156 std::cout << ConsoleColorTag(Console_Bold)
157 << "Please specify the common name (CN)"
158 << ConsoleColorTag(Console_Normal)
159 << " [" << Utility::GetFQDN() << "]: ";
161 std::getline(std::cin, answer);
164 answer = Utility::GetFQDN();
169 std::vector<std::string> endpoints;
171 String endpointBuffer;
173 std::cout << ConsoleColorTag(Console_Bold)
174 << "\nPlease specify the parent endpoint(s) (master or satellite) where this node should connect to:"
175 << ConsoleColorTag(Console_Normal) << "\n";
176 String parentEndpointName;
178 wizard_endpoint_loop_start:
180 std::cout << ConsoleColorTag(Console_Bold)
181 << "Master/Satellite Common Name" << ConsoleColorTag(Console_Normal)
182 << " (CN from your master/satellite node): ";
184 std::getline(std::cin, answer);
186 if (answer.empty()) {
187 Log(LogWarning, "cli", "Master/Satellite CN is required! Please retry.");
188 goto wizard_endpoint_loop_start;
191 endpointBuffer = answer;
192 endpointBuffer = endpointBuffer.Trim();
194 std::cout << "\nDo you want to establish a connection to the parent node "
195 << ConsoleColorTag(Console_Bold) << "from this node?"
196 << ConsoleColorTag(Console_Normal) << " [Y/n]: ";
198 std::getline (std::cin, answer);
199 boost::algorithm::to_lower(answer);
202 String parentEndpointPort = "5665";
204 if (choice.Contains("n")) {
205 connectToParent = false;
207 Log(LogWarning, "cli", "Node to master/satellite connection setup skipped");
208 std::cout << "Connection setup skipped. Please configure your parent node to\n"
209 << "connect to this node by setting the 'host' attribute for the node Endpoint object.\n";
212 connectToParent = true;
214 std::cout << ConsoleColorTag(Console_Bold)
215 << "Please specify the master/satellite connection information:"
216 << ConsoleColorTag(Console_Normal) << "\n"
217 << ConsoleColorTag(Console_Bold) << "Master/Satellite endpoint host"
218 << ConsoleColorTag(Console_Normal) << " (IP address or FQDN): ";
220 std::getline(std::cin, answer);
222 if (answer.empty()) {
223 Log(LogWarning, "cli", "Please enter the parent endpoint (master/satellite) connection information.");
224 goto wizard_endpoint_loop_start;
230 endpointBuffer += "," + tmp;
231 parentEndpointName = tmp;
233 std::cout << ConsoleColorTag(Console_Bold)
234 << "Master/Satellite endpoint port" << ConsoleColorTag(Console_Normal)
235 << " [" << parentEndpointPort << "]: ";
237 std::getline(std::cin, answer);
240 parentEndpointPort = answer;
242 endpointBuffer += "," + parentEndpointPort.Trim();
245 endpoints.push_back(endpointBuffer);
247 std::cout << ConsoleColorTag(Console_Bold) << "\nAdd more master/satellite endpoints?"
248 << ConsoleColorTag(Console_Normal) << " [y/N]: ";
249 std::getline (std::cin, answer);
251 boost::algorithm::to_lower(answer);
255 if (choice.Contains("y"))
256 goto wizard_endpoint_loop_start;
258 /* Extract parent node information. */
259 String parentHost, parentPort;
261 for (const String& endpoint : endpoints) {
262 std::vector<String> tokens = endpoint.Split(",");
264 if (tokens.size() > 1)
265 parentHost = tokens[1];
267 if (tokens.size() > 2)
268 parentPort = tokens[2];
271 /* workaround for fetching the master cert */
272 String certsDir = ApiListener::GetCertsDir();
273 Utility::MkDirP(certsDir, 0700);
275 String user = ScriptGlobal::Get("RunAsUser");
276 String group = ScriptGlobal::Get("RunAsGroup");
278 if (!Utility::SetFileOwnership(certsDir, user, group)) {
279 Log(LogWarning, "cli")
280 << "Cannot set ownership for user '" << user
281 << "' group '" << group
282 << "' on file '" << certsDir << "'. Verify it yourself!";
285 String nodeCert = certsDir + "/" + cn + ".crt";
286 String nodeKey = certsDir + "/" + cn + ".key";
288 if (Utility::PathExists(nodeKey))
289 NodeUtility::CreateBackupFile(nodeKey, true);
290 if (Utility::PathExists(nodeCert))
291 NodeUtility::CreateBackupFile(nodeCert);
293 if (PkiUtility::NewCert(cn, nodeKey, Empty, nodeCert) > 0) {
294 Log(LogCritical, "cli")
295 << "Failed to create new self-signed certificate for CN '"
296 << cn << "'. Please try again.";
300 /* fix permissions: root -> icinga daemon user */
301 if (!Utility::SetFileOwnership(nodeKey, user, group)) {
302 Log(LogWarning, "cli")
303 << "Cannot set ownership for user '" << user
304 << "' group '" << group
305 << "' on file '" << nodeKey << "'. Verify it yourself!";
308 std::shared_ptr<X509> trustedParentCert;
310 /* Check whether we should connect to the parent node and present its trusted certificate. */
311 if (connectToParent) {
312 //save-cert and store the master certificate somewhere
313 Log(LogInformation, "cli")
314 << "Fetching public certificate from master ("
315 << parentHost << ", " << parentPort << "):\n";
317 trustedParentCert = PkiUtility::FetchCert(parentHost, parentPort);
318 if (!trustedParentCert) {
319 Log(LogCritical, "cli", "Peer did not present a valid certificate.");
323 std::cout << ConsoleColorTag(Console_Bold) << "Parent certificate information:\n"
324 << ConsoleColorTag(Console_Normal) << PkiUtility::GetCertificateInformation(trustedParentCert)
325 << ConsoleColorTag(Console_Bold) << "\nIs this information correct?"
326 << ConsoleColorTag(Console_Normal) << " [y/N]: ";
328 std::getline (std::cin, answer);
329 boost::algorithm::to_lower(answer);
331 Log(LogWarning, "cli", "Process aborted.");
335 Log(LogInformation, "cli", "Received trusted parent certificate.\n");
339 String nodeCA = certsDir + "/ca.crt";
342 /* Check whether we can connect to the parent node and fetch the client and CA certificate. */
343 if (connectToParent) {
344 std::cout << ConsoleColorTag(Console_Bold)
345 << "\nPlease specify the request ticket generated on your Icinga 2 master "
346 << ConsoleColorTag(Console_Normal) << "(optional)"
347 << ConsoleColorTag(Console_Bold) << "."
348 << ConsoleColorTag(Console_Normal) << "\n"
349 << " (Hint: # icinga2 pki ticket --cn '" << cn << "'): ";
351 std::getline(std::cin, answer);
353 if (answer.empty()) {
354 std::cout << ConsoleColorTag(Console_Bold) << "\n"
355 << "No ticket was specified. Please approve the certificate signing request manually\n"
356 << "on the master (see 'icinga2 ca list' and 'icinga2 ca sign --help' for details)."
357 << ConsoleColorTag(Console_Normal) << "\n";
361 ticket = ticket.Trim();
363 if (ticket.IsEmpty()) {
364 Log(LogInformation, "cli")
365 << "Requesting certificate without a ticket.";
367 Log(LogInformation, "cli")
368 << "Requesting certificate with ticket '" << ticket << "'.";
371 if (Utility::PathExists(nodeCA))
372 NodeUtility::CreateBackupFile(nodeCA);
373 if (Utility::PathExists(nodeCert))
374 NodeUtility::CreateBackupFile(nodeCert);
376 if (PkiUtility::RequestCertificate(parentHost, parentPort, nodeKey,
377 nodeCert, nodeCA, trustedParentCert, ticket) > 0) {
378 Log(LogCritical, "cli")
379 << "Failed to fetch signed certificate from master '"
380 << parentHost << ", "
381 << parentPort << "'. Please try again.";
385 /* fix permissions (again) when updating the signed certificate */
386 if (!Utility::SetFileOwnership(nodeCert, user, group)) {
387 Log(LogWarning, "cli")
388 << "Cannot set ownership for user '" << user
389 << "' group '" << group << "' on file '"
390 << nodeCert << "'. Verify it yourself!";
393 /* We cannot retrieve the parent certificate.
394 * Tell the user to manually copy the ca.crt file
395 * into LocalStateDir + "/lib/icinga2/certs"
398 std::cout << ConsoleColorTag(Console_Bold)
399 << "\nNo connection to the parent node was specified.\n\n"
400 << "Please copy the public CA certificate from your master/satellite\n"
401 << "into '" << nodeCA << "' before starting Icinga 2.\n"
402 << ConsoleColorTag(Console_Normal);
404 if (Utility::PathExists(nodeCA)) {
405 std::cout << ConsoleColorTag(Console_Bold)
406 << "\nFound public CA certificate in '" << nodeCA << "'.\n"
407 << "Please verify that it is the same as on your master/satellite.\n"
408 << ConsoleColorTag(Console_Normal);
413 /* apilistener config */
414 std::cout << ConsoleColorTag(Console_Bold)
415 << "Please specify the API bind host/port "
416 << ConsoleColorTag(Console_Normal) << "(optional)"
417 << ConsoleColorTag(Console_Bold) << ":\n";
419 std::cout << ConsoleColorTag(Console_Bold)
420 << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: ";
422 std::getline(std::cin, answer);
424 String bindHost = answer;
425 bindHost = bindHost.Trim();
427 std::cout << ConsoleColorTag(Console_Bold)
428 << "Bind Port" << ConsoleColorTag(Console_Normal) << " []: ";
430 std::getline(std::cin, answer);
432 String bindPort = answer;
433 bindPort = bindPort.Trim();
435 std::cout << ConsoleColorTag(Console_Bold) << "\n"
436 << "Accept config from parent node?" << ConsoleColorTag(Console_Normal)
438 std::getline(std::cin, answer);
439 boost::algorithm::to_lower(answer);
442 String acceptConfig = choice.Contains("y") ? "true" : "false";
444 std::cout << ConsoleColorTag(Console_Bold)
445 << "Accept commands from parent node?" << ConsoleColorTag(Console_Normal)
447 std::getline(std::cin, answer);
448 boost::algorithm::to_lower(answer);
451 String acceptCommands = choice.Contains("y") ? "true" : "false";
455 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
456 << "Reconfiguring Icinga...\n"
457 << ConsoleColorTag(Console_Normal);
459 /* disable the notifications feature on client nodes */
460 Log(LogInformation, "cli", "Disabling the Notification feature.");
462 FeatureUtility::DisableFeatures({ "notification" });
464 Log(LogInformation, "cli", "Enabling the ApiListener feature.");
466 FeatureUtility::EnableFeatures({ "api" });
468 String apiConfPath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf";
469 NodeUtility::CreateBackupFile(apiConfPath);
472 String tempApiConfPath = Utility::CreateTempFile(apiConfPath + ".XXXXXX", 0644, fp);
475 << " * The API listener is used for distributed monitoring setups.\n"
477 << "object ApiListener \"api\" {\n"
478 << " accept_config = " << acceptConfig << "\n"
479 << " accept_commands = " << acceptCommands << "\n";
481 if (!bindHost.IsEmpty())
482 fp << " bind_host = \"" << bindHost << "\"\n";
483 if (!bindPort.IsEmpty())
484 fp << " bind_port = " << bindPort << "\n";
491 _unlink(apiConfPath.CStr());
494 if (rename(tempApiConfPath.CStr(), apiConfPath.CStr()) < 0) {
495 BOOST_THROW_EXCEPTION(posix_error()
496 << boost::errinfo_api_function("rename")
497 << boost::errinfo_errno(errno)
498 << boost::errinfo_file_name(tempApiConfPath));
501 /* Zones configuration. */
502 Log(LogInformation, "cli", "Generating local zones.conf.");
504 /* Setup command hardcodes this as FQDN */
505 String endpointName = cn;
507 /* Different local zone name. */
508 std::cout << "\nLocal zone name [" + endpointName + "]: ";
509 std::getline(std::cin, answer);
512 answer = endpointName;
514 String zoneName = answer;
515 zoneName = zoneName.Trim();
517 /* Different parent zone name. */
518 std::cout << "Parent zone name [master]: ";
519 std::getline(std::cin, answer);
524 String parentZoneName = answer;
525 parentZoneName = parentZoneName.Trim();
528 std::vector<String> globalZones { "global-templates", "director-global" };
530 std::cout << "\nDo you want to specify additional global zones? [y/N]: ";
532 std::getline(std::cin, answer);
533 boost::algorithm::to_lower(answer);
536 wizard_global_zone_loop_start:
537 if (choice.Contains("y")) {
538 std::cout << "\nPlease specify the name of the global Zone: ";
540 std::getline(std::cin, answer);
542 if (answer.empty()) {
543 std::cout << "\nName of the global Zone is required! Please retry.";
544 goto wizard_global_zone_loop_start;
547 String globalZoneName = answer;
548 globalZoneName = globalZoneName.Trim();
550 if (std::find(globalZones.begin(), globalZones.end(), globalZoneName) != globalZones.end()) {
551 std::cout << "The global zone '" << globalZoneName << "' is already specified."
553 goto wizard_global_zone_loop_start;
556 globalZones.push_back(globalZoneName);
558 std::cout << "\nDo you want to specify another global zone? [y/N]: ";
560 std::getline(std::cin, answer);
561 boost::algorithm::to_lower(answer);
564 if (choice.Contains("y"))
565 goto wizard_global_zone_loop_start;
567 Log(LogInformation, "cli", "No additional global Zones have been specified");
569 /* Generate node configuration. */
570 NodeUtility::GenerateNodeIcingaConfig(endpointName, zoneName, parentZoneName, endpoints, globalZones);
572 if (cn != Utility::GetFQDN()) {
573 Log(LogWarning, "cli")
574 << "CN '" << cn << "' does not match the default FQDN '"
575 << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!";
578 NodeUtility::UpdateConstant("NodeName", cn);
579 NodeUtility::UpdateConstant("ZoneName", cn);
581 if (!ticket.IsEmpty()) {
582 String ticketPath = ApiListener::GetCertsDir() + "/ticket";
584 String tempTicketPath = Utility::CreateTempFile(ticketPath + ".XXXXXX", 0600, fp);
586 if (!Utility::SetFileOwnership(tempTicketPath, user, group)) {
587 Log(LogWarning, "cli")
588 << "Cannot set ownership for user '" << user
589 << "' group '" << group
590 << "' on file '" << tempTicketPath << "'. Verify it yourself!";
598 _unlink(ticketPath.CStr());
601 if (rename(tempTicketPath.CStr(), ticketPath.CStr()) < 0) {
602 BOOST_THROW_EXCEPTION(posix_error()
603 << boost::errinfo_api_function("rename")
604 << boost::errinfo_errno(errno)
605 << boost::errinfo_file_name(tempTicketPath));
609 /* If no parent connection was made, the user must supply the ca.crt before restarting Icinga 2.*/
610 if (!connectToParent) {
611 Log(LogWarning, "cli")
612 << "No connection to the parent node was specified.\n\n"
613 << "Please copy the public CA certificate from your master/satellite\n"
614 << "into '" << nodeCA << "' before starting Icinga 2.\n";
616 Log(LogInformation, "cli", "Make sure to restart Icinga 2.");
619 /* Disable conf.d inclusion */
620 std::cout << "\nDo you want to disable the inclusion of the conf.d directory [Y/n]: ";
622 std::getline(std::cin, answer);
623 boost::algorithm::to_lower(answer);
626 if (choice.Contains("n"))
627 Log(LogInformation, "cli")
628 << "The deactivation of the conf.d directory was skipped.";
630 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
631 << "Disable the inclusion of the conf.d directory...\n"
632 << ConsoleColorTag(Console_Normal);
634 NodeUtility::UpdateConfiguration("\"conf.d\"", false, true);
640 int NodeWizardCommand::MasterSetup() const
645 std::cout << ConsoleColorTag(Console_Bold) << "Starting the Master setup routine...\n\n";
648 std::cout << ConsoleColorTag(Console_Bold)
649 << "Please specify the common name" << ConsoleColorTag(Console_Normal)
650 << " (CN) [" << Utility::GetFQDN() << "]: ";
652 std::getline(std::cin, answer);
655 answer = Utility::GetFQDN();
660 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
661 << "Reconfiguring Icinga...\n"
662 << ConsoleColorTag(Console_Normal);
664 /* check whether the user wants to generate a new certificate or not */
665 String existing_path = ApiListener::GetCertsDir() + "/" + cn + ".crt";
667 std::cout << ConsoleColorTag(Console_Normal)
668 << "Checking for existing certificates for common name '" << cn << "'...\n";
670 if (Utility::PathExists(existing_path)) {
671 std::cout << "Certificate '" << existing_path << "' for CN '"
672 << cn << "' already existing. Skipping certificate generation.\n";
674 std::cout << "Certificates not yet generated. Running 'api setup' now.\n";
675 ApiSetupUtility::SetupMasterCertificates(cn);
678 std::cout << ConsoleColorTag(Console_Bold)
679 << "Generating master configuration for Icinga 2.\n"
680 << ConsoleColorTag(Console_Normal);
682 ApiSetupUtility::SetupMasterApiUser();
684 if (!FeatureUtility::CheckFeatureEnabled("api"))
685 ApiSetupUtility::SetupMasterEnableApi();
687 std::cout << "'api' feature already enabled.\n";
689 /* Setup command hardcodes this as FQDN */
690 String endpointName = cn;
692 /* Different zone name. */
693 std::cout << "\nMaster zone name [master]: ";
694 std::getline(std::cin, answer);
699 String zoneName = answer;
700 zoneName = zoneName.Trim();
703 std::vector<String> globalZones { "global-templates", "director-global" };
705 std::cout << "\nDo you want to specify additional global zones? [y/N]: ";
707 std::getline(std::cin, answer);
708 boost::algorithm::to_lower(answer);
711 wizard_global_zone_loop_start:
712 if (choice.Contains("y")) {
713 std::cout << "\nPlease specify the name of the global Zone: ";
715 std::getline(std::cin, answer);
717 if (answer.empty()) {
718 std::cout << "\nName of the global Zone is required! Please retry.";
719 goto wizard_global_zone_loop_start;
722 String globalZoneName = answer;
723 globalZoneName = globalZoneName.Trim();
725 if (std::find(globalZones.begin(), globalZones.end(), globalZoneName) != globalZones.end()) {
726 std::cout << "The global zone '" << globalZoneName << "' is already specified."
728 goto wizard_global_zone_loop_start;
731 globalZones.push_back(globalZoneName);
733 std::cout << "\nDo you want to specify another global zone? [y/N]: ";
735 std::getline(std::cin, answer);
736 boost::algorithm::to_lower(answer);
739 if (choice.Contains("y"))
740 goto wizard_global_zone_loop_start;
742 Log(LogInformation, "cli", "No additional global Zones have been specified");
744 /* Generate master configuration. */
745 NodeUtility::GenerateNodeMasterIcingaConfig(endpointName, zoneName, globalZones);
747 /* apilistener config */
748 std::cout << ConsoleColorTag(Console_Bold)
749 << "Please specify the API bind host/port "
750 << ConsoleColorTag(Console_Normal) << "(optional)"
751 << ConsoleColorTag(Console_Bold) << ":\n";
753 std::cout << ConsoleColorTag(Console_Bold)
754 << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: ";
756 std::getline(std::cin, answer);
758 String bindHost = answer;
759 bindHost = bindHost.Trim();
761 std::cout << ConsoleColorTag(Console_Bold)
762 << "Bind Port" << ConsoleColorTag(Console_Normal) << " []: ";
764 std::getline(std::cin, answer);
766 String bindPort = answer;
767 bindPort = bindPort.Trim();
769 /* api feature is always enabled, check above */
770 String apiConfPath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf";
771 NodeUtility::CreateBackupFile(apiConfPath);
774 String tempApiConfPath = Utility::CreateTempFile(apiConfPath + ".XXXXXX", 0644, fp);
777 << " * The API listener is used for distributed monitoring setups.\n"
779 << "object ApiListener \"api\" {\n";
781 if (!bindHost.IsEmpty())
782 fp << " bind_host = \"" << bindHost << "\"\n";
783 if (!bindPort.IsEmpty())
784 fp << " bind_port = " << bindPort << "\n";
787 << " ticket_salt = TicketSalt\n"
793 _unlink(apiConfPath.CStr());
796 if (rename(tempApiConfPath.CStr(), apiConfPath.CStr()) < 0) {
797 BOOST_THROW_EXCEPTION(posix_error()
798 << boost::errinfo_api_function("rename")
799 << boost::errinfo_errno(errno)
800 << boost::errinfo_file_name(tempApiConfPath));
803 /* update constants.conf with NodeName = CN + TicketSalt = random value */
804 if (cn != Utility::GetFQDN()) {
805 Log(LogWarning, "cli")
806 << "CN '" << cn << "' does not match the default FQDN '"
807 << Utility::GetFQDN() << "'. Requires an update for the NodeName constant in constants.conf!";
810 Log(LogInformation, "cli", "Updating constants.conf.");
812 String constants_file = Application::GetSysconfDir() + "/icinga2/constants.conf";
814 NodeUtility::CreateBackupFile(constants_file);
816 NodeUtility::UpdateConstant("NodeName", cn);
817 NodeUtility::UpdateConstant("ZoneName", cn);
819 String salt = RandomString(16);
821 NodeUtility::UpdateConstant("TicketSalt", salt);
823 /* Disable conf.d inclusion */
824 std::cout << "\nDo you want to disable the inclusion of the conf.d directory [Y/n]: ";
826 std::getline(std::cin, answer);
827 boost::algorithm::to_lower(answer);
830 if (choice.Contains("n"))
831 Log(LogInformation, "cli")
832 << "The deactivation of the conf.d directory was skipped.";
834 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
835 << "Disable the inclusion of the conf.d directory...\n"
836 << ConsoleColorTag(Console_Normal);
838 NodeUtility::UpdateConfiguration("\"conf.d\"", false, true);
840 /* Include api-users.conf */
841 String apiUsersFilePath = Application::GetSysconfDir() + "/icinga2/conf.d/api-users.conf";
842 std::ifstream apiUsersFile(apiUsersFilePath);
844 std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundGreen)
845 << "Checking if api-users.conf exist...\n"
846 << ConsoleColorTag(Console_Normal);
849 NodeUtility::UpdateConfiguration("\"conf.d/api-users.conf\"", true, false);
851 Log(LogWarning, "cli")
852 << "Included file dosen't exist " << apiUsersFilePath;
855 std::cout << "Done.\n\n";