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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
require 'puppet'
require 'puppet/indirector'
# A class for reporting what happens on each client. Reports consist of
# two types of data: Logs and Metrics. Logs are the output that each
# change produces, and Metrics are all of the numerical data involved
# in the transaction.
class Puppet::Transaction::Report
extend Puppet::Indirector
indirects :report, :terminus_class => :processor
attr_accessor :configuration_version
attr_reader :resource_statuses, :logs, :metrics, :host, :time, :kind, :status
# This is necessary since Marshall doesn't know how to
# dump hash with default proc (see below @records)
def self.default_format
:yaml
end
def <<(msg)
@logs << msg
self
end
def add_times(name, value)
@external_times[name] = value
end
def add_metric(name, hash)
metric = Puppet::Util::Metric.new(name)
hash.each do |name, value|
metric.newvalue(name, value)
end
@metrics[metric.name] = metric
metric
end
def add_resource_status(status)
@resource_statuses[status.resource] = status
end
def compute_status(resource_metrics, change_metric)
if (resource_metrics["failed"] || 0) > 0
'failed'
elsif change_metric > 0
'changed'
else
'unchanged'
end
end
def finalize_report
resource_metrics = add_metric(:resources, calculate_resource_metrics)
add_metric(:time, calculate_time_metrics)
change_metric = calculate_change_metric
add_metric(:changes, {"total" => change_metric})
add_metric(:events, calculate_event_metrics)
@status = compute_status(resource_metrics, change_metric)
end
def initialize(kind, configuration_version=nil)
@metrics = {}
@logs = []
@resource_statuses = {}
@external_times ||= {}
@host = Puppet[:certname]
@time = Time.now
@kind = kind
@report_format = 2
@puppet_version = Puppet.version
@configuration_version = configuration_version
@status = 'failed' # assume failed until the report is finalized
end
def name
host
end
# Provide a human readable textual summary of this report.
def summary
report = raw_summary
ret = ""
report.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key|
ret += "#{Puppet::Util::Metric.labelize(key)}:\n"
report[key].keys.sort { |a,b|
# sort by label
if a == :total
1
elsif b == :total
-1
else
report[key][a].to_s <=> report[key][b].to_s
end
}.each do |label|
value = report[key][label]
next if value == 0
value = "%0.2f" % value if value.is_a?(Float)
ret += " %15s %s\n" % [Puppet::Util::Metric.labelize(label) + ":", value]
end
end
ret
end
# Provide a raw hash summary of this report.
def raw_summary
report = {}
@metrics.each do |name, metric|
key = metric.name.to_s
report[key] = {}
metric.values.each do |name, label, value|
report[key][name.to_s] = value
end
report[key]["total"] = 0 unless key == "time" or report[key].include?("total")
end
(report["time"] ||= {})["last_run"] = Time.now.tv_sec
report
end
# Based on the contents of this report's metrics, compute a single number
# that represents the report. The resulting number is a bitmask where
# individual bits represent the presence of different metrics.
def exit_status
status = 0
status |= 2 if @metrics["changes"]["total"] > 0
status |= 4 if @metrics["resources"]["failed"] > 0
status
end
def to_yaml_properties
(instance_variables - ["@external_times"]).sort
end
private
def calculate_change_metric
resource_statuses.map { |name, status| status.change_count || 0 }.inject(0) { |a,b| a+b }
end
def calculate_event_metrics
metrics = Hash.new(0)
metrics["total"] = 0
resource_statuses.each do |name, status|
metrics["total"] += status.events.length
status.events.each do |event|
metrics[event.status] += 1
end
end
metrics
end
def calculate_resource_metrics
metrics = Hash.new(0)
metrics["total"] = resource_statuses.length
resource_statuses.each do |name, status|
Puppet::Resource::Status::STATES.each do |state|
metrics[state.to_s] += 1 if status.send(state)
end
end
metrics
end
def calculate_time_metrics
metrics = Hash.new(0)
resource_statuses.each do |name, status|
type = Puppet::Resource.new(name).type
metrics[type.to_s.downcase] += status.evaluation_time if status.evaluation_time
end
@external_times.each do |name, value|
metrics[name.to_s.downcase] = value
end
metrics["total"] = metrics.values.inject(0) { |a,b| a+b }
metrics
end
end
|