summaryrefslogtreecommitdiffstats
path: root/lib/puppet/transaction/report.rb
blob: 24e69ea7ad19ffe576231329f0301c393972d081 (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
146
147
148
149
150
151
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_reader :resource_statuses, :logs, :metrics, :host, :time

    # 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
        return 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 calculate_metrics
        calculate_resource_metrics
        calculate_time_metrics
        calculate_change_metrics
        calculate_event_metrics
    end

    def initialize
        @metrics = {}
        @logs = []
        @resource_statuses = {}
        @external_times ||= {}
        @host = Puppet[:certname]
        @time = Time.now
    end

    def name
        host
    end

    # Provide a summary of this report.
    def summary
        ret = ""

        @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric|
            ret += "#{metric.label}:\n"
            metric.values.sort { |a,b|
                # sort by label
                if a[0] == :total
                    1
                elsif b[0] == :total
                    -1
                else
                    a[1] <=> b[1]
                end
            }.each do |name, label, value|
                next if value == 0
                if value.is_a?(Float)
                    value = "%0.2f" % value
                end
                ret += "   %15s %s\n" % [label + ":", value]
            end
        end
        return ret
    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
        return status
    end

    private

    def calculate_change_metrics
        metrics = Hash.new(0)
        resource_statuses.each do |name, status|
            metrics[:total] += status.change_count if status.change_count
        end

        add_metric(:changes, metrics)
    end

    def calculate_event_metrics
        metrics = Hash.new(0)
        resource_statuses.each do |name, status|
            metrics[:total] += status.events.length
            status.events.each do |event|
                metrics[event.status] += 1
            end
        end

        add_metric(:events, 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] += 1 if status.send(state)
            end
        end

        add_metric(:resources, 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

        add_metric(:time, metrics)
    end
end