mirror of https://github.com/Icinga/icinga2.git
CLI: Add basic repository <type> <command> & commit functionality
Still work in progress refs #7255
This commit is contained in:
parent
a4062066ca
commit
79be125f03
|
@ -26,6 +26,7 @@ set(cli_SOURCES
|
||||||
pkiutility.cpp
|
pkiutility.cpp
|
||||||
repositoryobjectcommand.cpp
|
repositoryobjectcommand.cpp
|
||||||
variablegetcommand.cpp variablelistcommand.cpp
|
variablegetcommand.cpp variablelistcommand.cpp
|
||||||
|
repositorycommitcommand.cpp repositoryobjectcommand.cpp repositoryutility.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ICINGA2_UNITY_BUILD)
|
if(ICINGA2_UNITY_BUILD)
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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/repositorycommitcommand.hpp"
|
||||||
|
#include "cli/repositoryutility.hpp"
|
||||||
|
#include "base/logger.hpp"
|
||||||
|
#include "base/application.hpp"
|
||||||
|
#include "base/convert.hpp"
|
||||||
|
#include "base/dynamicobject.hpp"
|
||||||
|
#include "base/dynamictype.hpp"
|
||||||
|
#include "base/serializer.hpp"
|
||||||
|
#include "base/netstring.hpp"
|
||||||
|
#include "base/stdiostream.hpp"
|
||||||
|
#include "base/debug.hpp"
|
||||||
|
#include "base/objectlock.hpp"
|
||||||
|
#include "base/console.hpp"
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
namespace po = boost::program_options;
|
||||||
|
|
||||||
|
REGISTER_CLICOMMAND("repository/commit", RepositoryCommitCommand);
|
||||||
|
|
||||||
|
String RepositoryCommitCommand::GetDescription(void) const
|
||||||
|
{
|
||||||
|
return "Commit Icinga 2 repository changes";
|
||||||
|
}
|
||||||
|
|
||||||
|
String RepositoryCommitCommand::GetShortDescription(void) const
|
||||||
|
{
|
||||||
|
return "commit repository changes";
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryCommitCommand::InitParameters(boost::program_options::options_description& visibleDesc,
|
||||||
|
boost::program_options::options_description& hiddenDesc) const
|
||||||
|
{
|
||||||
|
visibleDesc.add_options()
|
||||||
|
("simulate", "Simulate to-be-committed changes");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entry point for the "object list" CLI command.
|
||||||
|
*
|
||||||
|
* @returns An exit status.
|
||||||
|
*/
|
||||||
|
int RepositoryCommitCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
|
||||||
|
{
|
||||||
|
if (!ap.empty()) {
|
||||||
|
Log(LogWarning, "cli")
|
||||||
|
<< "Ignoring parameters: " << boost::algorithm::join(ap, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm.count("simulate")) {
|
||||||
|
RepositoryUtility::PrintChangeLog(std::cout);
|
||||||
|
std::cout << "Simulation not yet implemented.\n";
|
||||||
|
//TODO
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
RepositoryUtility::PrintChangeLog(std::cout);
|
||||||
|
RepositoryUtility::CommitChangeLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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 REPOSITORYCOMMITCOMMAND_H
|
||||||
|
#define REPOSITORYCOMMITCOMMAND_H
|
||||||
|
|
||||||
|
#include "base/dictionary.hpp"
|
||||||
|
#include "base/array.hpp"
|
||||||
|
#include "cli/clicommand.hpp"
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "object list" command.
|
||||||
|
*
|
||||||
|
* @ingroup cli
|
||||||
|
*/
|
||||||
|
class RepositoryCommitCommand : public CLICommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_PTR_TYPEDEFS(RepositoryCommitCommand);
|
||||||
|
|
||||||
|
virtual String GetDescription(void) const;
|
||||||
|
virtual String GetShortDescription(void) const;
|
||||||
|
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
|
||||||
|
boost::program_options::options_description& hiddenDesc) const;
|
||||||
|
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* REPOSITORYCOMMITCOMMAND_H */
|
|
@ -18,9 +18,14 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "cli/repositoryobjectcommand.hpp"
|
#include "cli/repositoryobjectcommand.hpp"
|
||||||
|
#include "cli/repositoryutility.hpp"
|
||||||
#include "base/logger.hpp"
|
#include "base/logger.hpp"
|
||||||
#include "base/application.hpp"
|
#include "base/application.hpp"
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
@ -67,6 +72,11 @@ String RepositoryObjectCommand::GetDescription(void) const
|
||||||
case RepositoryCommandList:
|
case RepositoryCommandList:
|
||||||
description = "Lists all";
|
description = "Lists all";
|
||||||
break;
|
break;
|
||||||
|
case RepositoryCommandSet:
|
||||||
|
description = "Set attributes for a";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
description += " " + m_Type + " object";
|
description += " " + m_Type + " object";
|
||||||
|
@ -91,6 +101,11 @@ String RepositoryObjectCommand::GetShortDescription(void) const
|
||||||
case RepositoryCommandList:
|
case RepositoryCommandList:
|
||||||
description = "lists all";
|
description = "lists all";
|
||||||
break;
|
break;
|
||||||
|
case RepositoryCommandSet:
|
||||||
|
description = "set attributes for a";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
description += " " + m_Type + " object";
|
description += " " + m_Type + " object";
|
||||||
|
@ -125,5 +140,48 @@ std::vector<String> RepositoryObjectCommand::GetPositionalSuggestions(const Stri
|
||||||
*/
|
*/
|
||||||
int RepositoryObjectCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
|
int RepositoryObjectCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
|
||||||
{
|
{
|
||||||
|
if (ap.empty()) {
|
||||||
|
Log(LogCritical, "cli")
|
||||||
|
<< "No object name given. Bailing out.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = ap[0];
|
||||||
|
|
||||||
|
std::vector<String> tokens;
|
||||||
|
Dictionary::Ptr attr = make_shared<Dictionary>();
|
||||||
|
|
||||||
|
std::vector<std::string> attrs = ap;
|
||||||
|
attrs.erase(attrs.begin()); //remove name
|
||||||
|
|
||||||
|
BOOST_FOREACH(const String& kv, attrs) {
|
||||||
|
boost::algorithm::split(tokens, kv, boost::is_any_of("="));
|
||||||
|
|
||||||
|
if (tokens.size() == 2)
|
||||||
|
attr->Set(tokens[0], tokens[1]);
|
||||||
|
else
|
||||||
|
Log(LogWarning, "cli")
|
||||||
|
<< "Cannot parse passed attributes for object '" << name << "': " << boost::algorithm::join(tokens, "=");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Command == RepositoryCommandList) {
|
||||||
|
RepositoryUtility::PrintObjects(std::cout, m_Type);
|
||||||
|
}
|
||||||
|
else if (m_Command == RepositoryCommandAdd) {
|
||||||
|
RepositoryUtility::AddObject(name, m_Type, attr);
|
||||||
|
}
|
||||||
|
else if (m_Command == RepositoryCommandRemove) {
|
||||||
|
RepositoryUtility::RemoveObject(name, m_Type);
|
||||||
|
}
|
||||||
|
else if (m_Command == RepositoryCommandSet) {
|
||||||
|
Log(LogWarning, "cli")
|
||||||
|
<< "Not implemented yet.\n";
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
Log(LogCritical, "cli")
|
||||||
|
<< "Invalid command '" << m_Command << "'specified.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@ enum RepositoryCommandType
|
||||||
{
|
{
|
||||||
RepositoryCommandAdd,
|
RepositoryCommandAdd,
|
||||||
RepositoryCommandRemove,
|
RepositoryCommandRemove,
|
||||||
RepositoryCommandList
|
RepositoryCommandList,
|
||||||
|
RepositoryCommandSet
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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/repositoryutility.hpp"
|
||||||
|
#include "cli/clicommand.hpp"
|
||||||
|
#include "base/logger.hpp"
|
||||||
|
#include "base/application.hpp"
|
||||||
|
#include "base/convert.hpp"
|
||||||
|
#include "base/serializer.hpp"
|
||||||
|
#include "base/netstring.hpp"
|
||||||
|
#include "base/stdiostream.hpp"
|
||||||
|
#include "base/debug.hpp"
|
||||||
|
#include "base/objectlock.hpp"
|
||||||
|
#include "base/console.hpp"
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
String RepositoryUtility::GetRepositoryDPath(void)
|
||||||
|
{
|
||||||
|
return Application::GetSysconfDir() + "/icinga2/repository.d";
|
||||||
|
}
|
||||||
|
|
||||||
|
String RepositoryUtility::GetRepositoryDObjectsPath(const String& type, const String& hostname)
|
||||||
|
{
|
||||||
|
if (type == "Host")
|
||||||
|
return GetRepositoryDPath() + "/hosts";
|
||||||
|
else if (type == "Service")
|
||||||
|
return GetRepositoryDPath() + "/hosts/" + hostname;
|
||||||
|
else if (type == "Zone")
|
||||||
|
return GetRepositoryDPath() + "/zones";
|
||||||
|
else if (type == "Endpoints")
|
||||||
|
return GetRepositoryDPath() + "/endpoints";
|
||||||
|
else
|
||||||
|
return GetRepositoryDPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
String RepositoryUtility::GetRepositoryChangeLogPath(void)
|
||||||
|
{
|
||||||
|
return Application::GetLocalStateDir() + "/lib/icinga2/repository";
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::PrintObjects(std::ostream& fp, const String& type)
|
||||||
|
{
|
||||||
|
std::vector<String> objects;
|
||||||
|
GetObjects(type, objects);
|
||||||
|
|
||||||
|
BOOST_FOREACH(const String& object, objects) {
|
||||||
|
Dictionary::Ptr obj = GetObjectFromRepository(GetRepositoryDObjectsPath(type) + "/" + object + ".conf");
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
fp << "Object Name: " << object << "\n";
|
||||||
|
fp << JsonSerialize(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public interface, only logs changes */
|
||||||
|
bool RepositoryUtility::AddObject(const String& name, const String& type, const Dictionary::Ptr& attr)
|
||||||
|
{
|
||||||
|
/* add a new changelog entry by timestamp */
|
||||||
|
String path = GetRepositoryChangeLogPath() + "/" + Convert::ToString(static_cast<long>(Utility::GetTime())) + ".change";
|
||||||
|
|
||||||
|
Dictionary::Ptr change = make_shared<Dictionary>();
|
||||||
|
|
||||||
|
change->Set("timestamp", Utility::GetTime());
|
||||||
|
change->Set("name", name);
|
||||||
|
change->Set("type", type);
|
||||||
|
change->Set("command", "add");
|
||||||
|
change->Set("attr", attr);
|
||||||
|
|
||||||
|
return WriteObjectToRepositoryChangeLog(path, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::RemoveObject(const String& name, const String& type)
|
||||||
|
{
|
||||||
|
/* add a new changelog entry by timestamp */
|
||||||
|
String path = GetRepositoryChangeLogPath() + "/" + Convert::ToString(static_cast<long>(Utility::GetTime())) + ".change";
|
||||||
|
|
||||||
|
Dictionary::Ptr change = make_shared<Dictionary>();
|
||||||
|
|
||||||
|
change->Set("timestamp", Utility::GetTime());
|
||||||
|
change->Set("name", name);
|
||||||
|
change->Set("type", type);
|
||||||
|
change->Set("command", "remove");
|
||||||
|
|
||||||
|
return WriteObjectToRepositoryChangeLog(path, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::CommitChangeLog(void)
|
||||||
|
{
|
||||||
|
GetChangeLog(boost::bind(RepositoryUtility::CommitChange, _1));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::PrintChangeLog(std::ostream& fp)
|
||||||
|
{
|
||||||
|
Array::Ptr changelog = make_shared<Array>();
|
||||||
|
|
||||||
|
GetChangeLog(boost::bind(RepositoryUtility::CollectChange, _1, boost::ref(changelog)));
|
||||||
|
|
||||||
|
ObjectLock olock(changelog);
|
||||||
|
|
||||||
|
std::cout << "Changes to be committed:\n";
|
||||||
|
|
||||||
|
BOOST_FOREACH(const Value& entry, changelog) {
|
||||||
|
std::cout << JsonSerialize(entry) << "\n"; //TODO better formatting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::SetObjectAttribute(const String& name, const String& type, const String& attr, const Value& val)
|
||||||
|
{
|
||||||
|
//TODO: Implement modification commands
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* internal implementation when changes are committed */
|
||||||
|
bool RepositoryUtility::AddObjectInternal(const String& name, const String& type, const Dictionary::Ptr& attr)
|
||||||
|
{
|
||||||
|
String path = GetRepositoryDObjectsPath(type, name) + "/" + name + ".conf";
|
||||||
|
|
||||||
|
return WriteObjectToRepository(path, name, type, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::RemoveObjectInternal(const String& name, const String& type)
|
||||||
|
{
|
||||||
|
String path = GetRepositoryDObjectsPath(type, name) + "/" + name + ".conf";
|
||||||
|
|
||||||
|
return RemoveObjectFileInternal(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::RemoveObjectFileInternal(const String& path)
|
||||||
|
{
|
||||||
|
if (!Utility::PathExists(path) ) {
|
||||||
|
Log(LogCritical, "cli", "Cannot remove '" + path + "'. Does not exist.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlink(path.CStr()) < 0) {
|
||||||
|
Log(LogCritical, "cli", "Cannot remove file '" + path +
|
||||||
|
"'. Failed with error code " + Convert::ToString(errno) + ", \"" + Utility::FormatErrorNumber(errno) + "\".");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::SetObjectAttributeInternal(const String& name, const String& type, const String& attr, const Value& val)
|
||||||
|
{
|
||||||
|
//Fixme
|
||||||
|
String path = GetRepositoryDObjectsPath(type, name) + "/" + name + ".conf";
|
||||||
|
|
||||||
|
Dictionary::Ptr obj = GetObjectFromRepository(path);
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
Log(LogCritical, "cli")
|
||||||
|
<< "Can't get object " << name << " from repository.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->Set(attr, val);
|
||||||
|
|
||||||
|
std::cout << "Writing object '" << name << "' to path '" << path << "'.\n";
|
||||||
|
|
||||||
|
//TODO: Create a patch file
|
||||||
|
if(!WriteObjectToRepository(path, name, type, obj)) {
|
||||||
|
Log(LogCritical, "cli")
|
||||||
|
<< "Can't write object " << name << " to repository.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::WriteObjectToRepository(const String& path, const String& name, const String& type, const Dictionary::Ptr& item)
|
||||||
|
{
|
||||||
|
Log(LogInformation, "cli", "Dumping config items to file '" + path + "'");
|
||||||
|
|
||||||
|
Utility::MkDirP(Utility::DirName(path), 0755);
|
||||||
|
|
||||||
|
String tempPath = path + ".tmp";
|
||||||
|
|
||||||
|
std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
|
||||||
|
SerializeObject(fp, name, type, item);
|
||||||
|
fp << std::endl;
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
_unlink(filename.CStr());
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (rename(tempPath.CStr(), path.CStr()) < 0) {
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("rename")
|
||||||
|
<< boost::errinfo_errno(errno)
|
||||||
|
<< boost::errinfo_file_name(tempPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::Ptr RepositoryUtility::GetObjectFromRepository(const String& filename)
|
||||||
|
{
|
||||||
|
//TODO: Parse existing configuration objects
|
||||||
|
return Dictionary::Ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepositoryUtility::WriteObjectToRepositoryChangeLog(const String& path, const Dictionary::Ptr& item)
|
||||||
|
{
|
||||||
|
Log(LogInformation, "cli", "Dumping changelog items to file '" + path + "'");
|
||||||
|
|
||||||
|
Utility::MkDirP(Utility::DirName(path), 0755);
|
||||||
|
|
||||||
|
String tempPath = path + ".tmp";
|
||||||
|
|
||||||
|
std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
|
||||||
|
fp << JsonSerialize(item);
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
_unlink(filename.CStr());
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (rename(tempPath.CStr(), path.CStr()) < 0) {
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("rename")
|
||||||
|
<< boost::errinfo_errno(errno)
|
||||||
|
<< boost::errinfo_file_name(tempPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::Ptr RepositoryUtility::GetObjectFromRepositoryChangeLog(const String& filename)
|
||||||
|
{
|
||||||
|
std::fstream fp;
|
||||||
|
fp.open(filename.CStr(), std::ifstream::in);
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return Dictionary::Ptr();
|
||||||
|
|
||||||
|
String content((std::istreambuf_iterator<char>(fp)), std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
return JsonDeserialize(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* collect functions
|
||||||
|
*/
|
||||||
|
bool RepositoryUtility::GetObjects(const String& type, std::vector<String>& objects)
|
||||||
|
{
|
||||||
|
String path = GetRepositoryDPath() + "/";
|
||||||
|
|
||||||
|
if (type == "service")
|
||||||
|
path = "hosts/*";
|
||||||
|
else
|
||||||
|
path = type;
|
||||||
|
|
||||||
|
if (!Utility::Glob(path + "/*.conf",
|
||||||
|
boost::bind(&RepositoryUtility::CollectObjects, _1, boost::ref(objects)), GlobFile)) {
|
||||||
|
Log(LogCritical, "cli", "Cannot access path '" + path + "'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::CollectObjects(const String& object_file, std::vector<String>& objects)
|
||||||
|
{
|
||||||
|
String object = Utility::BaseName(object_file);
|
||||||
|
boost::algorithm::replace_all(object, ".conf", "");
|
||||||
|
|
||||||
|
Log(LogDebug, "cli", "Adding object: " + object);
|
||||||
|
objects.push_back(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RepositoryUtility::GetChangeLog(const boost::function<void (const Dictionary::Ptr&)>& callback)
|
||||||
|
{
|
||||||
|
std::vector<String> changelog;
|
||||||
|
String path = GetRepositoryChangeLogPath() + "/";
|
||||||
|
|
||||||
|
if (!Utility::Glob(path + "/*.change",
|
||||||
|
boost::bind(&RepositoryUtility::CollectChangeLog, _1, boost::ref(changelog)), GlobFile)) {
|
||||||
|
Log(LogCritical, "cli", "Cannot access path '" + path + "'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort by timestamp ascending */
|
||||||
|
std::sort(changelog.begin(), changelog.end());
|
||||||
|
|
||||||
|
BOOST_FOREACH(const String& entry, changelog) {
|
||||||
|
Dictionary::Ptr change = GetObjectFromRepositoryChangeLog(path + entry + ".change");
|
||||||
|
|
||||||
|
Log(LogInformation, "cli")
|
||||||
|
<< "Collecting entry " << entry << "\n";
|
||||||
|
|
||||||
|
if (change)
|
||||||
|
callback(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::CollectChangeLog(const String& change_file, std::vector<String>& changelog)
|
||||||
|
{
|
||||||
|
String file = Utility::BaseName(change_file);
|
||||||
|
boost::algorithm::replace_all(file, ".change", "");
|
||||||
|
|
||||||
|
Log(LogDebug, "cli", "Adding change file: " + file);
|
||||||
|
changelog.push_back(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::CommitChange(const Dictionary::Ptr& change)
|
||||||
|
{
|
||||||
|
Log(LogInformation, "cli")
|
||||||
|
<< "Got change " << change->Get("name");
|
||||||
|
|
||||||
|
String name = change->Get("name");
|
||||||
|
String type = change->Get("type");
|
||||||
|
String command = change->Get("command");
|
||||||
|
Dictionary::Ptr attr;
|
||||||
|
|
||||||
|
if (change->Contains("attr")) {
|
||||||
|
attr = change->Get("attr");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == "add") {
|
||||||
|
AddObjectInternal(name, type, attr);
|
||||||
|
}
|
||||||
|
else if (command == "remove") {
|
||||||
|
RemoveObjectInternal(name, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::CollectChange(const Dictionary::Ptr& change, Array::Ptr& changes)
|
||||||
|
{
|
||||||
|
changes->Add(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print helpers for configuration
|
||||||
|
* TODO: Move into a separate class
|
||||||
|
*/
|
||||||
|
void RepositoryUtility::SerializeObject(std::ostream& fp, const String& name, const String& type, const Dictionary::Ptr& object)
|
||||||
|
{
|
||||||
|
fp << "object " << type << " \"" << name << "\" {\n";
|
||||||
|
BOOST_FOREACH(const Dictionary::Pair& kv, object) {
|
||||||
|
fp << "\t" << kv.first << " = ";
|
||||||
|
FormatValue(fp, kv.second);
|
||||||
|
fp << "\n";
|
||||||
|
}
|
||||||
|
fp << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::FormatValue(std::ostream& fp, const Value& val)
|
||||||
|
{
|
||||||
|
if (val.IsObjectType<Array>()) {
|
||||||
|
FormatArray(fp, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val.IsString()) {
|
||||||
|
fp << "\"" << Convert::ToString(val) << "\"";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp << Convert::ToString(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepositoryUtility::FormatArray(std::ostream& fp, const Array::Ptr& arr)
|
||||||
|
{
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
fp << "[ ";
|
||||||
|
|
||||||
|
if (arr) {
|
||||||
|
ObjectLock olock(arr);
|
||||||
|
BOOST_FOREACH(const Value& value, arr) {
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
fp << ", ";
|
||||||
|
|
||||||
|
FormatValue(fp, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
fp << " ";
|
||||||
|
|
||||||
|
fp << "]";
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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 REPOSITORYUTILITY_H
|
||||||
|
#define REPOSITORYUTILITY_H
|
||||||
|
|
||||||
|
#include "base/i2-base.hpp"
|
||||||
|
#include "base/dictionary.hpp"
|
||||||
|
#include "base/array.hpp"
|
||||||
|
#include "base/value.hpp"
|
||||||
|
#include "base/string.hpp"
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup cli
|
||||||
|
*/
|
||||||
|
class RepositoryUtility
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static String GetRepositoryDPath(void);
|
||||||
|
static String GetRepositoryDObjectsPath(const String& type, const String& hostname = Empty);
|
||||||
|
static String GetRepositoryChangeLogPath(void);
|
||||||
|
|
||||||
|
static void PrintObjects(std::ostream& fp, const String& type);
|
||||||
|
|
||||||
|
static void PrintChangeLog(std::ostream& fp);
|
||||||
|
|
||||||
|
static bool AddObject(const String& name, const String& type, const Dictionary::Ptr& attr);
|
||||||
|
static bool RemoveObject(const String& name, const String& type);
|
||||||
|
|
||||||
|
static bool SetObjectAttribute(const String& name, const String& type, const String& attr, const Value& val);
|
||||||
|
|
||||||
|
static bool CommitChangeLog(void);
|
||||||
|
|
||||||
|
static bool GetObjects(const String& type, std::vector<String>& objects);
|
||||||
|
private:
|
||||||
|
RepositoryUtility(void);
|
||||||
|
|
||||||
|
static bool RemoveObjectFileInternal(const String& path);
|
||||||
|
|
||||||
|
static bool AddObjectInternal(const String& name, const String& type, const Dictionary::Ptr& attr);
|
||||||
|
static bool RemoveObjectInternal(const String& name, const String& type);
|
||||||
|
static bool SetObjectAttributeInternal(const String& name, const String& type, const String& attr, const Value& val);
|
||||||
|
|
||||||
|
/* repository.d */
|
||||||
|
static void CollectObjects(const String& object_file, std::vector<String>& objects);
|
||||||
|
static bool WriteObjectToRepository(const String& path, const String& name, const String& type, const Dictionary::Ptr& item);
|
||||||
|
static Dictionary::Ptr GetObjectFromRepository(const String& filename);
|
||||||
|
|
||||||
|
/* changelog */
|
||||||
|
static void CollectChangeLog(const String& change_file, std::vector<String>& changelog);
|
||||||
|
static bool WriteObjectToRepositoryChangeLog(const String& path, const Dictionary::Ptr& item);
|
||||||
|
static Dictionary::Ptr GetObjectFromRepositoryChangeLog(const String& filename);
|
||||||
|
|
||||||
|
static bool GetChangeLog(const boost::function<void (const Dictionary::Ptr&)>& callback);
|
||||||
|
static void CommitChange(const Dictionary::Ptr& change);
|
||||||
|
static void CollectChange(const Dictionary::Ptr& change, Array::Ptr& changes);
|
||||||
|
|
||||||
|
/* config print helpers */
|
||||||
|
static void SerializeObject(std::ostream& fp, const String& name, const String& type, const Dictionary::Ptr& object);
|
||||||
|
static void FormatValue(std::ostream& fp, const Value& val);
|
||||||
|
static void FormatArray(std::ostream& fp, const Array::Ptr& arr);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* REPOSITORYUTILITY_H */
|
Loading…
Reference in New Issue