chef_sous_vide 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ require "chef/config"
2
+ require "chef/json_compat"
3
+ require "chef/log"
4
+
5
+ module SousVide
6
+ module Outputs
7
+ # Saves the report to a JSON file on a node. The file will be saved to chef cache directory.
8
+ #
9
+ # Outputs::JsonFile.new
10
+ #
11
+ # By the report will be saved to "<chef-cache-path>/sous-vide-report.json".
12
+ class JsonFile
13
+ def initialize(logger: logger)
14
+ @logger = logger
15
+ end
16
+
17
+ def call(run_data:, node_data:, resources_data:)
18
+ log "=============== #{self.class.name} ==============="
19
+ log ""
20
+ log "Processing #{resources_data.size} resources."
21
+
22
+ json_data = resources_data.map do |tracked|
23
+ tracked.to_h.merge(node_data).merge(run_data)
24
+ end
25
+
26
+ ::Chef::FileCache.store("sous-vide-report.json",
27
+ ::Chef::JSONCompat.to_json_pretty(json_data))
28
+
29
+ log "The report is in #{Chef::Config[:file_cache_path]}/sous-vide-report.json file."
30
+ log ""
31
+ end
32
+
33
+ def log(*args)
34
+ message = args.compact.join(" ")
35
+ logger.info(message)
36
+ end
37
+
38
+ def logger
39
+ @logger ||= ::Chef::Log
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,66 @@
1
+ require "net/http"
2
+ require "time"
3
+ require "uri"
4
+
5
+ module SousVide
6
+ module Outputs
7
+ # Makes a POST request to a configured endpoint. Logstash & Elasticsearch friendly format.
8
+ #
9
+ # JsonHTTP.new(url: "http://localhost:9200/endpoint", max_retries: 10)
10
+ class JsonHTTP
11
+ def initialize(url:, max_retries: 0, logger: nil)
12
+ @endpoint = URI(url)
13
+ @logger = logger
14
+
15
+ @max_retries = max_retries || 2
16
+ @http_client = Net::HTTP.new(@endpoint.host, @endpoint.port)
17
+ end
18
+
19
+ def call(run_data:, node_data:, resources_data:)
20
+ log "=============== #{self.class.name} ==============="
21
+ log ""
22
+ log "Processing #{resources_data.size} resources."
23
+ log "Target: #{@endpoint.to_s}"
24
+
25
+ resources_data.each do |tracked|
26
+ _path = @endpoint.path == "" ? "/" : @endpoint.path
27
+ post_request = Net::HTTP::Post.new(_path, "Content-Type" => "application/json")
28
+
29
+ payload = tracked.to_h.merge(node_data).merge(run_data)
30
+ payload["@timestamp"] = Time.parse(payload[:chef_resource_started_at]).iso8601(3)
31
+
32
+ post_request.body = payload.to_json
33
+
34
+ call_with_retries(post_request)
35
+ end
36
+
37
+ log "All resources processed."
38
+ log ""
39
+ end
40
+
41
+ def call_with_retries(nethttp_request)
42
+ _retry = 0
43
+ begin
44
+ @http_client.request(nethttp_request)
45
+ rescue
46
+ if _retry < @max_retries
47
+ _retry += 1
48
+ sleep 2
49
+ retry
50
+ else
51
+ raise
52
+ end
53
+ end
54
+ end
55
+
56
+ def log(*args)
57
+ message = args.compact.join(" ")
58
+ logger.info(message)
59
+ end
60
+
61
+ def logger
62
+ @logger ||= ::Chef::Log
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,48 @@
1
+ module SousVide
2
+ module Outputs
3
+ # Prints the report to the logger (usually Chef logger).
4
+ #
5
+ # Outputs::Logger.new
6
+ class Logger
7
+ def initialize(logger: nil)
8
+ @logger = logger
9
+ end
10
+
11
+ def call(run_data:, node_data:, resources_data:)
12
+ log "=============== #{self.class.name} ==============="
13
+ log ""
14
+ log "Processing #{resources_data.size} resources."
15
+ log ""
16
+
17
+ resources_data.each do |tracked|
18
+ log("#{tracked.execution_order}.", tracked.to_s, tracked.status,
19
+ "(#{tracked.duration_ms.to_i} ms)", tracked.execution_phase)
20
+ end
21
+
22
+ log ""
23
+ log "Node info:"
24
+ log ""
25
+ log "Name:", node_data[:chef_node_instance_id]
26
+ log "IP Address:", node_data[:chef_node_ipv4]
27
+ log "Role:", node_data[:chef_node_role]
28
+ log ""
29
+ log "Run info:"
30
+ log ""
31
+ log "ID:", run_data[:chef_run_id]
32
+ log "Started at:", run_data[:chef_run_started_at]
33
+ log "Completed at:", run_data[:chef_run_completed_at]
34
+ log "Success:", run_data[:chef_run_success]
35
+ log ""
36
+ end
37
+
38
+ def log(*args)
39
+ message = args.compact.join(' ')
40
+ logger.info(message)
41
+ end
42
+
43
+ def logger
44
+ @logger ||= ::Chef::Log
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module SousVide
2
+ module Outputs
3
+ # Combines multiple outputs
4
+ #
5
+ # es = Outputs::ES.new ...
6
+ # log = Outputs::Logger.new ...
7
+ # multi = Outputs::Multi.new(es, log)
8
+ class Multi
9
+ def initialize(*outputs)
10
+ @outputs = outputs
11
+ end
12
+
13
+ def call(run_data:, node_data:, resources_data:)
14
+ @outputs.each do |output|
15
+ output.call(run_data: run_data, node_data: node_data,
16
+ resources_data: resources_data)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ module SousVide
2
+ # == SousVide::TrackedResource
3
+ #
4
+ # This is a very simple data structure SousVide uses to capture interesting
5
+ # information.
6
+ class TrackedResource
7
+ attr_accessor :type,
8
+ :name,
9
+ :action,
10
+ :status,
11
+ :duration_ms,
12
+ :guard_description,
13
+ :execution_phase,
14
+ :execution_order,
15
+ :notifying_resource,
16
+ :notification_type,
17
+ :before_notifications,
18
+ :immediate_notifications,
19
+ :delayed_notifications,
20
+ :retries,
21
+ :error_output,
22
+ :error_source,
23
+ :cookbook_name,
24
+ :cookbook_recipe,
25
+ :source_line,
26
+ :started_at,
27
+ :completed_at
28
+
29
+ attr_accessor :chef_resource_handle
30
+
31
+ def initialize(name:, action:, type:)
32
+ @name = name
33
+ @action = action
34
+ @type = type
35
+
36
+ @status = "unprocessed"
37
+ @duration_ms = nil
38
+ @guard_description = nil
39
+
40
+ @retries = 0
41
+ @error_output = nil
42
+ @error_source = nil
43
+ end
44
+
45
+ def to_s
46
+ "#{@type}[#{@name}]##{@action}"
47
+ end
48
+
49
+ def to_h
50
+ {
51
+ chef_resource: "#{@type}[#{@name}]##{@action}",
52
+ chef_resource_name: @name,
53
+ chef_resource_type: @type,
54
+ chef_resource_cookbook: @cookbook_name,
55
+ chef_resource_recipe: @cookbook_recipe,
56
+ chef_resource_action: @action,
57
+ chef_resource_guard: @guard_description,
58
+ chef_resource_duration_ms: @duration_ms,
59
+ chef_resource_error_output: @error_output,
60
+ chef_resource_error_source: @error_source,
61
+ chef_resource_retries: @retries,
62
+ chef_resource_notified_by: @notifying_resource,
63
+ chef_resource_notified_via: @notification_type,
64
+ chef_resource_before_notifications: @before_notifications,
65
+ chef_resource_immediate_notifications: @immediate_notifications,
66
+ chef_resource_delayed_notifications: @delayed_notifications,
67
+ chef_resource_order: @execution_order,
68
+ chef_resource_execution_phase: @execution_phase,
69
+ chef_resource_started_at: @started_at,
70
+ chef_resource_completed_at: @completed_at,
71
+ chef_resource_status: @status
72
+ }
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module SousVide
2
+ VERSION = "0.1.0".freeze
3
+ end
data/sous_vide.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "sous_vide/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "chef_sous_vide"
7
+ spec.version = SousVide::VERSION
8
+ spec.authors = ["robuye"]
9
+ spec.email = ["rulejczyk@gmail.com"]
10
+
11
+ spec.summary = "Sous vide cooking utilizes precise temperature control with circulation to produce results that you can’t achieve through any other cooking technique."
12
+ spec.description = "SousVide is a Chef Handler who will precisely track a converge process of your recipes and help you become a better cook."
13
+ spec.homepage = "https://github.com/lonelyplanet/sous_vide"
14
+ spec.license = "MIT"
15
+
16
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(cookbooks|kitchen|features)/}) }
19
+ end
20
+
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "chef", "~> 12.17.44"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.17"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "cucumber", "~> 3.1.2"
30
+ spec.add_development_dependency "pry"
31
+ spec.add_development_dependency "test-kitchen"
32
+ spec.add_development_dependency "kitchen-docker"
33
+ spec.add_development_dependency "kitchen-transport-rsync"
34
+ spec.add_development_dependency "berkshelf"
35
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef_sous_vide
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - robuye
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 12.17.44
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 12.17.44
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.17'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cucumber
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.1.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.1.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: test-kitchen
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: kitchen-docker
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: kitchen-transport-rsync
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: berkshelf
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: SousVide is a Chef Handler who will precisely track a converge process
140
+ of your recipes and help you become a better cook.
141
+ email:
142
+ - rulejczyk@gmail.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - ".travis.yml"
149
+ - Berksfile
150
+ - Berksfile.lock
151
+ - Gemfile
152
+ - Gemfile.lock
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - bin/console
157
+ - bin/setup
158
+ - kitchen.yml
159
+ - lib/sous_vide.rb
160
+ - lib/sous_vide/event_methods.rb
161
+ - lib/sous_vide/handler.rb
162
+ - lib/sous_vide/outputs/json_file.rb
163
+ - lib/sous_vide/outputs/json_http.rb
164
+ - lib/sous_vide/outputs/logger.rb
165
+ - lib/sous_vide/outputs/multi.rb
166
+ - lib/sous_vide/tracked_resource.rb
167
+ - lib/sous_vide/version.rb
168
+ - sous_vide.gemspec
169
+ homepage: https://github.com/lonelyplanet/sous_vide
170
+ licenses:
171
+ - MIT
172
+ metadata: {}
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubyforge_project:
189
+ rubygems_version: 2.5.2
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: Sous vide cooking utilizes precise temperature control with circulation to
193
+ produce results that you can’t achieve through any other cooking technique.
194
+ test_files: []