summaryrefslogtreecommitdiffstats
path: root/lib/cli/objectlistcommand.cpp
blob: 3bcb31512cd2a689d207409bda7fd2872de427ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#include "cli/objectlistcommand.hpp"
#include "cli/objectlistutility.hpp"
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/convert.hpp"
#include "base/configobject.hpp"
#include "base/configtype.hpp"
#include "base/json.hpp"
#include "base/netstring.hpp"
#include "base/stdiostream.hpp"
#include "base/debug.hpp"
#include "base/objectlock.hpp"
#include "base/console.hpp"
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sys/stat.h>

using namespace icinga;
namespace po = boost::program_options;

REGISTER_CLICOMMAND("object/list", ObjectListCommand);

String ObjectListCommand::GetDescription() const
{
	return "Lists all Icinga 2 objects.";
}

String ObjectListCommand::GetShortDescription() const
{
	return "lists all objects";
}

void ObjectListCommand::InitParameters(boost::program_options::options_description& visibleDesc,
	boost::program_options::options_description& hiddenDesc) const
{
	visibleDesc.add_options()
		("count,c", "display object counts by types")
		("name,n", po::value<std::string>(), "filter by name matches")
		("type,t", po::value<std::string>(), "filter by type matches");
}

static time_t GetCtime(const String& path)
{
#ifdef _WIN32
	struct _stat statbuf;
	int rc = _stat(path.CStr(), &statbuf);
#else /* _WIN32 */
	struct stat statbuf;
	int rc = stat(path.CStr(), &statbuf);
#endif /* _WIN32 */

	return rc ? 0 : statbuf.st_ctime;
}

/**
 * The entry point for the "object list" CLI command.
 *
 * @returns An exit status.
 */
int ObjectListCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
{
	String objectfile = Configuration::ObjectsPath;

	if (!Utility::PathExists(objectfile)) {
		Log(LogCritical, "cli")
			<< "Cannot open objects file '" << Configuration::ObjectsPath << "'.";
		Log(LogCritical, "cli", "Run 'icinga2 daemon -C --dump-objects' to validate config and generate the cache file.");
		return 1;
	}

	std::fstream fp;
	fp.open(objectfile.CStr(), std::ios_base::in);

	StdioStream::Ptr sfp = new StdioStream(&fp, false);
	unsigned long objects_count = 0;
	std::map<String, int> type_count;

	String name_filter, type_filter;

	if (vm.count("name"))
		name_filter = vm["name"].as<std::string>();
	if (vm.count("type"))
		type_filter = vm["type"].as<std::string>();

	bool first = true;

	String message;
	StreamReadContext src;
	for (;;) {
		StreamReadStatus srs = NetString::ReadStringFromStream(sfp, &message, src);

		if (srs == StatusEof)
			break;

		if (srs != StatusNewItem)
			continue;

		ObjectListUtility::PrintObject(std::cout, first, message, type_count, name_filter, type_filter);
		objects_count++;
	}

	sfp->Close();
	fp.close();

	if (vm.count("count")) {
		if (!first)
			std::cout << "\n";

		PrintTypeCounts(std::cout, type_count);
		std::cout << "\n";
	}

	Log(LogNotice, "cli")
		<< "Parsed " << objects_count << " objects.";

	auto objectsPathCtime (GetCtime(Configuration::ObjectsPath));
	auto varsPathCtime (GetCtime(Configuration::VarsPath));

	if (objectsPathCtime < varsPathCtime) {
		Log(LogWarning, "cli")
			<< "This data is " << Utility::FormatDuration(varsPathCtime - objectsPathCtime)
			<< " older than the last Icinga config (re)load. It may be outdated. Consider running 'icinga2 daemon -C --dump-objects' first.";
	}

	return 0;
}

void ObjectListCommand::PrintTypeCounts(std::ostream& fp, const std::map<String, int>& type_count)
{
	typedef std::map<String, int>::value_type TypeCount;

	for (const TypeCount& kv : type_count) {
		fp << "Found " << kv.second << " " << kv.first << " object";

		if (kv.second != 1)
			fp << "s";

		fp << ".\n";
	}
}