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
|
#
# Author:: Tyler Ball (<tball@chef.io>)
#
# Copyright:: Copyright 2014-2016, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require "securerandom"
class Chef
class Audit
class AuditData
attr_reader :node_name, :run_id, :control_groups
attr_accessor :start_time, :end_time
def initialize(node_name, run_id)
@node_name = node_name
@run_id = run_id
@control_groups = []
end
def add_control_group(control_group)
control_groups << control_group
end
def to_hash
{
:node_name => node_name,
:run_id => run_id,
:start_time => start_time,
:end_time => end_time,
:control_groups => control_groups.collect { |c| c.to_hash },
}
end
end
class ControlGroupData
attr_reader :name, :status, :number_succeeded, :number_failed, :controls, :metadata
def initialize(name, metadata = {})
@status = "success"
@controls = []
@number_succeeded = 0
@number_failed = 0
@name = name
@metadata = metadata
end
def example_success(control_data)
@number_succeeded += 1
control = create_control(control_data)
control.status = "success"
controls << control
control
end
def example_failure(control_data, details)
@number_failed += 1
@status = "failure"
control = create_control(control_data)
control.details = details if details
control.status = "failure"
controls << control
control
end
def to_hash
# We sort it so the examples appear in the output in the same order
# they appeared in the recipe
controls.sort! { |x, y| x.line_number <=> y.line_number }
h = {
:name => name,
:status => status,
:number_succeeded => number_succeeded,
:number_failed => number_failed,
:controls => controls.collect { |c| c.to_hash },
}
# If there is a duplicate key, metadata will overwrite it
add_display_only_data(h).merge(metadata)
end
private
def create_control(control_data)
ControlData.new(control_data)
end
# The id and control sequence number are ephemeral data - they are not needed
# to be persisted and can be regenerated at will. They are only needed
# for display purposes.
def add_display_only_data(group)
group[:id] = SecureRandom.uuid
group[:controls].collect!.with_index do |c, i|
# i is zero-indexed, and we want the display one-indexed
c[:sequence_number] = i + 1
c
end
group
end
end
class ControlData
attr_reader :name, :resource_type, :resource_name, :context, :line_number
attr_accessor :status, :details
def initialize(control_data = {})
control_data.each do |k, v|
self.instance_variable_set("@#{k}", v)
end
end
def to_hash
h = {
:name => name,
:status => status,
:details => details,
:resource_type => resource_type,
:resource_name => resource_name,
}
h[:context] = context || []
h
end
end
end
end
|