CLI: Add feature enable/disable auto-completion

Refactor feature list code.
Add disabled features to list output.
Add more console colors.
Change output to stdout for general logging.

fixes #7381
fixes #7415
refs #7376
This commit is contained in:
Michael Friedrich 2014-10-18 19:31:52 +02:00
parent 29bf22f324
commit e98d719e5b
9 changed files with 193 additions and 55 deletions

View File

@ -18,7 +18,7 @@
set(cli_SOURCES set(cli_SOURCES
agentaddcommand.cpp agentblackandwhitelistcommand.cpp agentlistcommand.cpp agentremovecommand.cpp agentaddcommand.cpp agentblackandwhitelistcommand.cpp agentlistcommand.cpp agentremovecommand.cpp
agentsetcommand.cpp agentsetupcommand.cpp agentupdateconfigcommand.cpp agentwizardcommand.cpp agentutility.cpp agentsetcommand.cpp agentsetupcommand.cpp agentupdateconfigcommand.cpp agentwizardcommand.cpp agentutility.cpp
featureenablecommand.cpp featuredisablecommand.cpp featurelistcommand.cpp featureenablecommand.cpp featuredisablecommand.cpp featurelistcommand.cpp featureutility.cpp
objectlistcommand.cpp objectlistcommand.cpp
pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkiticketcommand.cpp pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkiticketcommand.cpp
repositoryobjectcommand.cpp repositoryobjectcommand.cpp

View File

@ -18,10 +18,12 @@
******************************************************************************/ ******************************************************************************/
#include "cli/featuredisablecommand.hpp" #include "cli/featuredisablecommand.hpp"
#include "cli/featureutility.hpp"
#include "base/logger_fwd.hpp" #include "base/logger_fwd.hpp"
#include "base/clicommand.hpp" #include "base/clicommand.hpp"
#include "base/application.hpp" #include "base/application.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/console.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
#include <fstream> #include <fstream>
@ -42,10 +44,9 @@ String FeatureDisableCommand::GetShortDescription(void) const
return "disables specified feature"; return "disables specified feature";
} }
void FeatureDisableCommand::InitParameters(boost::program_options::options_description& visibleDesc, std::vector<String> FeatureDisableCommand::GetPositionalSuggestions(const String& word) const
boost::program_options::options_description& hiddenDesc) const
{ {
/* Command doesn't support any parameters. */ return FeatureUtility::GetFieldCompletionSuggestions(FeatureCommandDisable, word);
} }
/** /**
@ -89,7 +90,8 @@ int FeatureDisableCommand::Run(const boost::program_options::variables_map& vm,
continue; continue;
} }
Log(LogInformation, "cli", "Disabling feature " + feature + " in '" + features_enabled_dir + "'."); std::cout << "Disabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature
<< ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n";
} }
if (!errors.empty()) { if (!errors.empty()) {

View File

@ -38,8 +38,7 @@ public:
virtual String GetDescription(void) const; virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const; virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc, virtual std::vector<String> GetPositionalSuggestions(const String& word) const;
boost::program_options::options_description& hiddenDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
}; };

View File

@ -18,16 +18,15 @@
******************************************************************************/ ******************************************************************************/
#include "cli/featureenablecommand.hpp" #include "cli/featureenablecommand.hpp"
#include "cli/featureutility.hpp"
#include "base/logger_fwd.hpp" #include "base/logger_fwd.hpp"
#include "base/clicommand.hpp" #include "base/clicommand.hpp"
#include "base/application.hpp" #include "base/application.hpp"
#include "base/convert.hpp" #include "base/convert.hpp"
#include "base/console.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
#include <fstream> #include <fstream>
#include <vector>
#include <string>
#include <fstream>
using namespace icinga; using namespace icinga;
namespace po = boost::program_options; namespace po = boost::program_options;
@ -44,10 +43,9 @@ String FeatureEnableCommand::GetShortDescription(void) const
return "enables specified feature"; return "enables specified feature";
} }
void FeatureEnableCommand::InitParameters(boost::program_options::options_description& visibleDesc, std::vector<String> FeatureEnableCommand::GetPositionalSuggestions(const String& word) const
boost::program_options::options_description& hiddenDesc) const
{ {
/* Command doesn't support any parameters. */ return FeatureUtility::GetFieldCompletionSuggestions(FeatureCommandEnable, word);
} }
/** /**
@ -93,8 +91,6 @@ int FeatureEnableCommand::Run(const boost::program_options::variables_map& vm, c
continue; continue;
} }
Log(LogInformation, "cli", "Enabling feature '" + feature + "' in '" + features_enabled_dir + "'.");
#ifndef _WIN32 #ifndef _WIN32
if (symlink(source.CStr(), target.CStr()) < 0) { if (symlink(source.CStr(), target.CStr()) < 0) {
Log(LogCritical, "cli", "Cannot enable feature '" + feature + "'. Linking source '" + source + "' to target file '" + target + Log(LogCritical, "cli", "Cannot enable feature '" + feature + "'. Linking source '" + source + "' to target file '" + target +
@ -113,6 +109,9 @@ int FeatureEnableCommand::Run(const boost::program_options::variables_map& vm, c
fp << "include \"../features-available/" << feature << ".conf\"" << std::endl; fp << "include \"../features-available/" << feature << ".conf\"" << std::endl;
fp.close(); fp.close();
#endif /* _WIN32 */ #endif /* _WIN32 */
std::cout << "Enabling feature " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << feature
<< ConsoleColorTag(Console_Normal) << ". Make sure to restart Icinga 2 for these changes to take effect.\n";
} }
if (!errors.empty()) { if (!errors.empty()) {

View File

@ -38,10 +38,8 @@ public:
virtual String GetDescription(void) const; virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const; virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc, virtual std::vector<String> GetPositionalSuggestions(const String& word) const;
boost::program_options::options_description& hiddenDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
}; };
} }

View File

@ -18,15 +18,14 @@
******************************************************************************/ ******************************************************************************/
#include "cli/featurelistcommand.hpp" #include "cli/featurelistcommand.hpp"
#include "cli/featureutility.hpp"
#include "base/logger_fwd.hpp" #include "base/logger_fwd.hpp"
#include "base/clicommand.hpp" #include "base/clicommand.hpp"
#include "base/application.hpp" #include "base/convert.hpp"
#include "base/console.hpp"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp> #include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace icinga; using namespace icinga;
namespace po = boost::program_options; namespace po = boost::program_options;
@ -54,36 +53,23 @@ int FeatureListCommand::Run(const boost::program_options::variables_map& vm, con
Log(LogWarning, "cli", "Ignoring parameters: " + boost::algorithm::join(ap, " ")); Log(LogWarning, "cli", "Ignoring parameters: " + boost::algorithm::join(ap, " "));
} }
#ifdef _WIN32
//TODO: Add Windows support
Log(LogInformation, "cli", "This command is not available on Windows.");
#else
std::vector<String> enabled_features;
std::vector<String> available_features; std::vector<String> available_features;
std::vector<String> disabled_features;
std::vector<String> enabled_features;
if (!Utility::Glob(Application::GetSysconfDir() + "/icinga2/features-enabled/*.conf", if (!FeatureUtility::GetFeatures(FeaturesAvailable, available_features))
boost::bind(&FeatureListCommand::CollectFeatures, _1, boost::ref(enabled_features)), GlobFile)) { return 1;
Log(LogCritical, "cli", "Cannot access path '" + Application::GetSysconfDir() + "/icinga2/features-enabled/'."); if (!FeatureUtility::GetFeatures(FeaturesDisabled, disabled_features))
} return 1;
if (!FeatureUtility::GetFeatures(FeaturesEnabled, enabled_features))
return 1;
if (!Utility::Glob(Application::GetSysconfDir() + "/icinga2/features-available/*.conf", std::cout << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << "Available features: " << ConsoleColorTag(Console_Normal)
boost::bind(&FeatureListCommand::CollectFeatures, _1, boost::ref(available_features)), GlobFile)) { << boost::algorithm::join(available_features, " ") << "\n";
Log(LogCritical, "cli", "Cannot access path '" + Application::GetSysconfDir() + "/icinga2/available-available/'."); std::cout << ConsoleColorTag(Console_ForegroundRed | Console_Bold) << "Disabled features: " << ConsoleColorTag(Console_Normal)
} << boost::algorithm::join(disabled_features, " ") << "\n";
std::cout << ConsoleColorTag(Console_ForegroundGreen | Console_Bold) << "Enabled features: " << ConsoleColorTag(Console_Normal)
Log(LogInformation, "cli", "Available features: " + boost::algorithm::join(available_features, " ")); << boost::algorithm::join(enabled_features, " ") << "\n";
Log(LogInformation, "cli", "---");
Log(LogInformation, "cli", "Enabled features: " + boost::algorithm::join(enabled_features, " "));
#endif /* _WIN32 */
return 0; return 0;
} }
void FeatureListCommand::CollectFeatures(const String& feature_file, std::vector<String>& features)
{
String feature = Utility::BaseName(feature_file);
boost::algorithm::replace_all(feature, ".conf", "");
Log(LogDebug, "cli", "Adding feature: " + feature);
features.push_back(feature);
}

View File

@ -39,10 +39,6 @@ public:
virtual String GetDescription(void) const; virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const; virtual String GetShortDescription(void) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
private:
static void CollectFeatures(const String& feature_file, std::vector<String>& features);
}; };
} }

View File

@ -0,0 +1,99 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "cli/featureutility.hpp"
#include "base/logger_fwd.hpp"
#include "base/clicommand.hpp"
#include "base/application.hpp"
#include <boost/foreach.hpp>
#include <boost/algorithm/string/replace.hpp>
using namespace icinga;
std::vector<String> FeatureUtility::GetFieldCompletionSuggestions(FeatureCommandType fctype, const String& word)
{
std::vector<String> cache;
std::vector<String> suggestions;
if (fctype == FeatureCommandEnable) {
/* only suggest features not already enabled */
GetFeatures(FeaturesDisabled, cache);
} else if (fctype == FeatureCommandDisable) {
/* suggest all enabled features */
GetFeatures(FeaturesEnabled, cache);
}
std::sort(cache.begin(), cache.end());
BOOST_FOREACH(const String& suggestion, cache) {
if (suggestion.Find(word) == 0)
suggestions.push_back(suggestion);
}
return suggestions;
}
bool FeatureUtility::GetFeatures(FeatureType ftype, std::vector<String>& features)
{
String path = Application::GetSysconfDir() + "/icinga2/";
/* disabled = available-enabled */
if (ftype == FeaturesDisabled) {
std::vector<String> enabled;
std::vector<String> available;
GetFeatures(FeaturesAvailable, available);
GetFeatures(FeaturesEnabled, enabled);
std::sort(available.begin(), available.end());
std::sort(enabled.begin(), enabled.end());
std::set_difference(
available.begin(), available.end(),
enabled.begin(), enabled.end(),
std::back_inserter(features)
);
return true;
} else {
if (ftype == FeaturesAvailable)
path += "features-available/";
else if (ftype == FeaturesEnabled)
path += "features-enabled/";
else {
Log(LogCritical, "cli", "Unknown feature type passed. Bailing out.");
return false;
}
if (!Utility::Glob(path + "/*.conf",
boost::bind(&FeatureUtility::CollectFeatures, _1, boost::ref(features)), GlobFile)) {
Log(LogCritical, "cli", "Cannot access path '" + path + "'.");
return false;
}
}
return true;
}
void FeatureUtility::CollectFeatures(const String& feature_file, std::vector<String>& features)
{
String feature = Utility::BaseName(feature_file);
boost::algorithm::replace_all(feature, ".conf", "");
Log(LogDebug, "cli", "Adding feature: " + feature);
features.push_back(feature);
}

View File

@ -0,0 +1,59 @@
/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software Foundation *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#ifndef FEATUREUTILITY_H
#define FEATUREUTILITY_H
#include "base/i2-base.hpp"
#include "base/qstring.hpp"
#include <vector>
namespace icinga
{
enum FeatureType
{
FeaturesAvailable,
FeaturesEnabled,
FeaturesDisabled
};
enum FeatureCommandType
{
FeatureCommandEnable,
FeatureCommandDisable
};
/**
* @ingroup cli
*/
class FeatureUtility
{
public:
static std::vector<String> GetFieldCompletionSuggestions(FeatureCommandType fctype, const String& word);
static bool GetFeatures(FeatureType ftype, std::vector<String>& features);
private:
FeatureUtility(void);
static void CollectFeatures(const String& feature_file, std::vector<String>& features);
};
}
#endif /* FEATUREUTILITY_H */