summaryrefslogtreecommitdiff
path: root/lib/chef/audit/control_group_data.rb
blob: 4dffbdf3dde529c1617b50f2ad8a9286cc529bf6 (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
#
# 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