From dd9905813eddec469b588222100e5fc33ae48c4e Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Sat, 5 Dec 2015 12:13:48 +0900 Subject: [PATCH 01/23] Introduce Reporter. --- lib/itamae.rb | 1 + lib/itamae/reporter.rb | 11 +++++++++++ lib/itamae/reporter/base.rb | 12 ++++++++++++ lib/itamae/reporter/debug.rb | 9 +++++++++ lib/itamae/runner.rb | 18 ++++++++++++++++++ 5 files changed, 51 insertions(+) create mode 100644 lib/itamae/reporter.rb create mode 100644 lib/itamae/reporter/base.rb create mode 100644 lib/itamae/reporter/debug.rb diff --git a/lib/itamae.rb b/lib/itamae.rb index 889201c4..cd6c417a 100644 --- a/lib/itamae.rb +++ b/lib/itamae.rb @@ -3,6 +3,7 @@ require "itamae/cli" require "itamae/recipe" require "itamae/resource" +require "itamae/reporter" require "itamae/recipe_children" require "itamae/logger" require "itamae/node" diff --git a/lib/itamae/reporter.rb b/lib/itamae/reporter.rb new file mode 100644 index 00000000..858ade4e --- /dev/null +++ b/lib/itamae/reporter.rb @@ -0,0 +1,11 @@ +require 'itamae/reporter/base' +require 'itamae/reporter/debug' + +module Itamae + module Reporter + def self.from_type(type) + class_name = type.split('_').map(&:capitalize).join + self.const_get(class_name) + end + end +end diff --git a/lib/itamae/reporter/base.rb b/lib/itamae/reporter/base.rb new file mode 100644 index 00000000..9bd60afb --- /dev/null +++ b/lib/itamae/reporter/base.rb @@ -0,0 +1,12 @@ +module Itamae + module Reporter + class Base + def initialize(options) + end + + def event(type, payload = {}) + raise NotImplementedError + end + end + end +end diff --git a/lib/itamae/reporter/debug.rb b/lib/itamae/reporter/debug.rb new file mode 100644 index 00000000..23e469ed --- /dev/null +++ b/lib/itamae/reporter/debug.rb @@ -0,0 +1,9 @@ +module Itamae + module Reporter + class Debug < Base + def event(type, payload = {}) + Itamae.logger.info("EVENT:#{type} #{payload}") + end + end + end +end diff --git a/lib/itamae/runner.rb b/lib/itamae/runner.rb index d7c51a15..e41f298c 100644 --- a/lib/itamae/runner.rb +++ b/lib/itamae/runner.rb @@ -35,6 +35,8 @@ def initialize(backend, options) @backend = backend @options = options + prepare_reporters + @node = create_node @tmpdir = "/tmp/itamae_tmp" @children = RecipeChildren.new @@ -79,6 +81,12 @@ def save_profile(path) end end + def report(*args) + @reporters.each do |r| + r.event(*args) + end + end + private def create_node hash = {} @@ -108,5 +116,15 @@ def create_node Node.new(hash, @backend) end + + def prepare_reporters + @reporters = (@options[:reporters] || []).map do |reporter| + type = reporter.delete('type') + unless type + raise "#{type} field is not set" + end + Reporter.from_type(type).new(reporter) + end + end end end From 87dc1b5976b47cfd3caab71f25d28f42588955e5 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Sun, 6 Dec 2015 23:06:40 +0900 Subject: [PATCH 02/23] Require reporter class if loading fails. --- lib/itamae/reporter.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/itamae/reporter.rb b/lib/itamae/reporter.rb index 858ade4e..82f4db94 100644 --- a/lib/itamae/reporter.rb +++ b/lib/itamae/reporter.rb @@ -4,8 +4,19 @@ module Itamae module Reporter def self.from_type(type) + first_time = true + class_name = type.split('_').map(&:capitalize).join self.const_get(class_name) + rescue NameError + require "itamae/reporter/#{type}" + + if first_time + first_time = false + retry + else + raise + end end end end From 020c28262cb1576d7e40171afd0909ce086a02ab Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Sun, 6 Dec 2015 23:10:55 +0900 Subject: [PATCH 03/23] Runner#report_with_block --- lib/itamae/runner.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/itamae/runner.rb b/lib/itamae/runner.rb index e41f298c..9ac81a61 100644 --- a/lib/itamae/runner.rb +++ b/lib/itamae/runner.rb @@ -81,12 +81,19 @@ def save_profile(path) end end - def report(*args) + def report(event_name, *args) @reporters.each do |r| - r.event(*args) + r.event(event_name, *args) end end + def report_with_block(event_name, *args) + report("begin_#{event_name}".to_sym, *args) + yield + ensure + report("end_#{event_name}".to_sym, *args) + end + private def create_node hash = {} From 05c1daa95bfabc7a05f108f2faf0af0f07dc2e0a Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Sun, 6 Dec 2015 23:11:11 +0900 Subject: [PATCH 04/23] Report begin and end of recipes and resources. --- lib/itamae/recipe.rb | 8 +++++--- lib/itamae/resource/base.rb | 32 +++++++++++++++++--------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/itamae/recipe.rb b/lib/itamae/recipe.rb index e923fa24..fc0621dc 100644 --- a/lib/itamae/recipe.rb +++ b/lib/itamae/recipe.rb @@ -61,9 +61,11 @@ def load(vars = {}) def run show_banner - Itamae.logger.with_indent do - @children.run - run_delayed_notifications + @runner.report_with_block(:recipe, path: @path) do + Itamae.logger.with_indent do + @children.run + run_delayed_notifications + end end end diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index 36ce7faa..a4ab3092 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -121,26 +121,28 @@ def initialize(recipe, resource_name, &block) end def run(specific_action = nil) - Itamae.logger.debug "#{resource_type}[#{resource_name}]" + runner.report_with_block(:resource) do + Itamae.logger.debug "#{resource_type}[#{resource_name}]" + + Itamae.logger.with_indent_if(Itamae.logger.debug?) do + if do_not_run_because_of_only_if? + Itamae.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of only_if attribute" + return + elsif do_not_run_because_of_not_if? + Itamae.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of not_if attribute" + return + end - Itamae.logger.with_indent_if(Itamae.logger.debug?) do - if do_not_run_because_of_only_if? - Itamae.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of only_if attribute" - return - elsif do_not_run_because_of_not_if? - Itamae.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of not_if attribute" - return - end + [specific_action || attributes.action].flatten.each do |action| + run_action(action) + end - [specific_action || attributes.action].flatten.each do |action| - run_action(action) + verify unless runner.dry_run? + notify if updated? end - verify unless runner.dry_run? - notify if updated? + @updated = false end - - @updated = false rescue Backend::CommandExecutionError Itamae.logger.error "#{resource_type}[#{resource_name}] Failed." exit 2 From 3118e01a6ae6ad946352e09c6a37e6eed9c485fa Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 11:06:51 +0900 Subject: [PATCH 05/23] Store options into @options. --- lib/itamae/reporter/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/itamae/reporter/base.rb b/lib/itamae/reporter/base.rb index 9bd60afb..90d73f24 100644 --- a/lib/itamae/reporter/base.rb +++ b/lib/itamae/reporter/base.rb @@ -2,6 +2,7 @@ module Itamae module Reporter class Base def initialize(options) + @options = options end def event(type, payload = {}) From 73beb25ec03eb6dfd3996d0aa72e5aab406c7e06 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 16:28:05 +0900 Subject: [PATCH 06/23] Refactor resource_type method. --- lib/itamae/resource/base.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index a4ab3092..11e198ad 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -153,15 +153,7 @@ def action_nothing end def resource_type - humps = [] - self.class.name.split("::").last.each_char do |c| - if "A" <= c && c <= "Z" - humps << c.downcase - else - humps.last << c - end - end - humps.join('_') + self.class.name.split("::").last.scan(/[A-Z][^A-Z]+/).map(&:downcase).join('_') end private From 0cad98c9d83754e26d16c7aed40737e96433cfde Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 16:41:59 +0900 Subject: [PATCH 07/23] Wrap run_action with report_with_block. --- lib/itamae/resource/base.rb | 62 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index 11e198ad..007b1cfe 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -161,45 +161,47 @@ def resource_type alias_method :current, :current_attributes def run_action(action) - original_attributes = @attributes # preserve and restore later - @current_action = action + runner.report_with_block(:action) do + original_attributes = @attributes # preserve and restore later + @current_action = action - clear_current_attributes - - Itamae.logger.debug "#{resource_type}[#{resource_name}] action: #{action}" - - return if action == :nothing - - Itamae.logger.with_indent_if(Itamae.logger.debug?) do - Itamae.logger.debug "(in pre_action)" - pre_action + clear_current_attributes - Itamae.logger.debug "(in set_current_attributes)" - set_current_attributes + Itamae.logger.debug "#{resource_type}[#{resource_name}] action: #{action}" - Itamae.logger.debug "(in show_differences)" - show_differences + return if action == :nothing - method_name = "action_#{action}" - if runner.dry_run? - unless respond_to?(method_name) - Itamae.logger.error "action #{action.inspect} is unavailable" - end - else - args = [method_name] - if method(method_name).arity == 1 - # for plugin compatibility - args << runner.options + Itamae.logger.with_indent_if(Itamae.logger.debug?) do + Itamae.logger.debug "(in pre_action)" + pre_action + + Itamae.logger.debug "(in set_current_attributes)" + set_current_attributes + + Itamae.logger.debug "(in show_differences)" + show_differences + + method_name = "action_#{action}" + if runner.dry_run? + unless respond_to?(method_name) + Itamae.logger.error "action #{action.inspect} is unavailable" + end + else + args = [method_name] + if method(method_name).arity == 1 + # for plugin compatibility + args << runner.options + end + + public_send(*args) end - public_send(*args) + updated! if different? end - updated! if different? + @current_action = nil + @attributes = original_attributes end - - @current_action = nil - @attributes = original_attributes end def clear_current_attributes From 1021812b26f18fff080dca8405ad902bf5b071c1 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 17:19:13 +0900 Subject: [PATCH 08/23] Change event name to *_started, *_failed and *_completed. --- lib/itamae/runner.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/itamae/runner.rb b/lib/itamae/runner.rb index 9ac81a61..fe3969cf 100644 --- a/lib/itamae/runner.rb +++ b/lib/itamae/runner.rb @@ -88,10 +88,13 @@ def report(event_name, *args) end def report_with_block(event_name, *args) - report("begin_#{event_name}".to_sym, *args) + report("#{event_name}_started".to_sym, *args) yield - ensure - report("end_#{event_name}".to_sym, *args) + rescue + report("#{event_name}_failed".to_sym, *args) + raise + else + report("#{event_name}_completed".to_sym, *args) end private From a482ccb61d8e091c17fe469dc805fce440c228f0 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 17:19:51 +0900 Subject: [PATCH 09/23] Store stack of recipes, resources and actions. --- lib/itamae/reporter/base.rb | 19 ++++++++++++++++++- lib/itamae/reporter/debug.rb | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/itamae/reporter/base.rb b/lib/itamae/reporter/base.rb index 90d73f24..576403f2 100644 --- a/lib/itamae/reporter/base.rb +++ b/lib/itamae/reporter/base.rb @@ -3,10 +3,27 @@ module Reporter class Base def initialize(options) @options = options + + @recipes = [] + @resources = [] + @actions = [] end def event(type, payload = {}) - raise NotImplementedError + case type + when :recipe_started + @recipes << payload + when :recipe_completed, :recipe_failed + @recipes.pop + when :resource_started + @resources << payload + when :resource_completed, :resource_failed + @resources.pop + when :action_started + @actions << payload + when :action_completed, :action_failed + @actions.pop + end end end end diff --git a/lib/itamae/reporter/debug.rb b/lib/itamae/reporter/debug.rb index 23e469ed..b5d4ea81 100644 --- a/lib/itamae/reporter/debug.rb +++ b/lib/itamae/reporter/debug.rb @@ -2,6 +2,7 @@ module Itamae module Reporter class Debug < Base def event(type, payload = {}) + super Itamae.logger.info("EVENT:#{type} #{payload}") end end From f4d8cd59d0677331d6631cedc17e51efc51e0fd5 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 17:20:29 +0900 Subject: [PATCH 10/23] Report resource_type, resource_name and action. --- lib/itamae/resource/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index 007b1cfe..ec6b0028 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -121,7 +121,7 @@ def initialize(recipe, resource_name, &block) end def run(specific_action = nil) - runner.report_with_block(:resource) do + runner.report_with_block(:resource, resource_type: resource_type, resource_name: resource_name) do Itamae.logger.debug "#{resource_type}[#{resource_name}]" Itamae.logger.with_indent_if(Itamae.logger.debug?) do @@ -161,7 +161,7 @@ def resource_type alias_method :current, :current_attributes def run_action(action) - runner.report_with_block(:action) do + runner.report_with_block(:action, action: action) do original_attributes = @attributes # preserve and restore later @current_action = action From e07f8350b96a37050119a49067b38c3c64dfae71 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 17:58:33 +0900 Subject: [PATCH 11/23] attribute_changed event. --- lib/itamae/resource/base.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index ec6b0028..85481a44 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -196,7 +196,10 @@ def run_action(action) public_send(*args) end - updated! if different? + if different? + updated! + runner.report(:attribute_changed, from: @current_attributes, to: @attributes) + end end @current_action = nil From 9ef60129baa22713ef3e29eaa8564b945d3186d4 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 18:00:42 +0900 Subject: [PATCH 12/23] Show diff of new file. --- lib/itamae/resource/file.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/itamae/resource/file.rb b/lib/itamae/resource/file.rb index 69e0ad7d..26c11bcc 100644 --- a/lib/itamae/resource/file.rb +++ b/lib/itamae/resource/file.rb @@ -50,8 +50,8 @@ def show_differences super - if current.exist && @temppath - show_file_diff + if @temppath + compare_file end end @@ -113,8 +113,14 @@ def action_edit(options) private - def show_file_diff - diff = run_command(["diff", "-u", attributes.path, @temppath], error: false) + def compare_file + compare_to = if current.exist + attributes.path + else + '/dev/null' + end + + diff = run_command(["diff", "-u", compare_to, @temppath], error: false) if diff.exit_status == 0 # no change Itamae.logger.debug "file content will not change" From e26ea51f47471d9e5df405e6fb5a5b25833892c8 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 18:00:55 +0900 Subject: [PATCH 13/23] Report file_content_changed event. --- lib/itamae/resource/file.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/itamae/resource/file.rb b/lib/itamae/resource/file.rb index 26c11bcc..4f6e1521 100644 --- a/lib/itamae/resource/file.rb +++ b/lib/itamae/resource/file.rb @@ -138,6 +138,7 @@ def compare_file Itamae.logger.info line.chomp end end + runner.report(:file_content_changed, diff: diff.stdout) end end From c3d826eaf16476e95c5a0bc994a32649812a1fce Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 18:11:05 +0900 Subject: [PATCH 14/23] Rename reporter to handler. --- lib/itamae.rb | 2 +- lib/itamae/{reporter.rb => handler.rb} | 8 ++++---- lib/itamae/{reporter => handler}/base.rb | 2 +- lib/itamae/{reporter => handler}/debug.rb | 2 +- lib/itamae/runner.rb | 12 ++++++------ 5 files changed, 13 insertions(+), 13 deletions(-) rename lib/itamae/{reporter.rb => handler.rb} (70%) rename lib/itamae/{reporter => handler}/base.rb (97%) rename lib/itamae/{reporter => handler}/debug.rb (90%) diff --git a/lib/itamae.rb b/lib/itamae.rb index cd6c417a..24eabbd5 100644 --- a/lib/itamae.rb +++ b/lib/itamae.rb @@ -3,7 +3,7 @@ require "itamae/cli" require "itamae/recipe" require "itamae/resource" -require "itamae/reporter" +require "itamae/handler" require "itamae/recipe_children" require "itamae/logger" require "itamae/node" diff --git a/lib/itamae/reporter.rb b/lib/itamae/handler.rb similarity index 70% rename from lib/itamae/reporter.rb rename to lib/itamae/handler.rb index 82f4db94..da3ae8d4 100644 --- a/lib/itamae/reporter.rb +++ b/lib/itamae/handler.rb @@ -1,15 +1,15 @@ -require 'itamae/reporter/base' -require 'itamae/reporter/debug' +require 'itamae/handler/base' +require 'itamae/handler/debug' module Itamae - module Reporter + module Handler def self.from_type(type) first_time = true class_name = type.split('_').map(&:capitalize).join self.const_get(class_name) rescue NameError - require "itamae/reporter/#{type}" + require "itamae/handler/#{type}" if first_time first_time = false diff --git a/lib/itamae/reporter/base.rb b/lib/itamae/handler/base.rb similarity index 97% rename from lib/itamae/reporter/base.rb rename to lib/itamae/handler/base.rb index 576403f2..8153351c 100644 --- a/lib/itamae/reporter/base.rb +++ b/lib/itamae/handler/base.rb @@ -1,5 +1,5 @@ module Itamae - module Reporter + module Handler class Base def initialize(options) @options = options diff --git a/lib/itamae/reporter/debug.rb b/lib/itamae/handler/debug.rb similarity index 90% rename from lib/itamae/reporter/debug.rb rename to lib/itamae/handler/debug.rb index b5d4ea81..af7f289c 100644 --- a/lib/itamae/reporter/debug.rb +++ b/lib/itamae/handler/debug.rb @@ -1,5 +1,5 @@ module Itamae - module Reporter + module Handler class Debug < Base def event(type, payload = {}) super diff --git a/lib/itamae/runner.rb b/lib/itamae/runner.rb index fe3969cf..fe1e214e 100644 --- a/lib/itamae/runner.rb +++ b/lib/itamae/runner.rb @@ -35,7 +35,7 @@ def initialize(backend, options) @backend = backend @options = options - prepare_reporters + prepare_handlers @node = create_node @tmpdir = "/tmp/itamae_tmp" @@ -82,7 +82,7 @@ def save_profile(path) end def report(event_name, *args) - @reporters.each do |r| + @handers.each do |r| r.event(event_name, *args) end end @@ -127,13 +127,13 @@ def create_node Node.new(hash, @backend) end - def prepare_reporters - @reporters = (@options[:reporters] || []).map do |reporter| - type = reporter.delete('type') + def prepare_handlers + @handler = (@options[:handlers] || []).map do |handler| + type = handler.delete('type') unless type raise "#{type} field is not set" end - Reporter.from_type(type).new(reporter) + Handler.from_type(type).new(handler) end end end From c6f6691670deadf29fa83040752ef3f75f30d462 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 18:28:34 +0900 Subject: [PATCH 15/23] Introduce HandlerProxy. --- lib/itamae.rb | 1 + lib/itamae/handler_proxy.rb | 38 +++++++++++++++++++++++++++++++++++++ lib/itamae/recipe.rb | 2 +- lib/itamae/resource/base.rb | 6 +++--- lib/itamae/resource/file.rb | 2 +- lib/itamae/runner.rb | 26 ++++++------------------- 6 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 lib/itamae/handler_proxy.rb diff --git a/lib/itamae.rb b/lib/itamae.rb index 24eabbd5..ff143137 100644 --- a/lib/itamae.rb +++ b/lib/itamae.rb @@ -4,6 +4,7 @@ require "itamae/recipe" require "itamae/resource" require "itamae/handler" +require "itamae/handler_proxy" require "itamae/recipe_children" require "itamae/logger" require "itamae/node" diff --git a/lib/itamae/handler_proxy.rb b/lib/itamae/handler_proxy.rb new file mode 100644 index 00000000..d54001a6 --- /dev/null +++ b/lib/itamae/handler_proxy.rb @@ -0,0 +1,38 @@ +module Itamae + class HandlerProxy + def initialize + @instances = [] + end + + def <<(instance) + @instances << instance + end + + def event(*args, &block) + if block_given? + _event_with_block(*args, &block) + else + _event(*args) + end + end + + private + + def _event(*args) + @instances.each do |i| + i.event(*args) + end + end + + def _event_with_block(event_name, *args, &block) + event("#{event_name}_started".to_sym, *args) + block.call + rescue + event("#{event_name}_failed".to_sym, *args) + raise + else + event("#{event_name}_completed".to_sym, *args) + end + end +end + diff --git a/lib/itamae/recipe.rb b/lib/itamae/recipe.rb index fc0621dc..68eafce0 100644 --- a/lib/itamae/recipe.rb +++ b/lib/itamae/recipe.rb @@ -61,7 +61,7 @@ def load(vars = {}) def run show_banner - @runner.report_with_block(:recipe, path: @path) do + @runner.handler.event(:recipe, path: @path) do Itamae.logger.with_indent do @children.run run_delayed_notifications diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index 85481a44..ca645e3b 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -121,7 +121,7 @@ def initialize(recipe, resource_name, &block) end def run(specific_action = nil) - runner.report_with_block(:resource, resource_type: resource_type, resource_name: resource_name) do + runner.handler.event(:resource, resource_type: resource_type, resource_name: resource_name) do Itamae.logger.debug "#{resource_type}[#{resource_name}]" Itamae.logger.with_indent_if(Itamae.logger.debug?) do @@ -161,7 +161,7 @@ def resource_type alias_method :current, :current_attributes def run_action(action) - runner.report_with_block(:action, action: action) do + runner.handler.event(:action, action: action) do original_attributes = @attributes # preserve and restore later @current_action = action @@ -198,7 +198,7 @@ def run_action(action) if different? updated! - runner.report(:attribute_changed, from: @current_attributes, to: @attributes) + runner.handler.event(:attribute_changed, from: @current_attributes, to: @attributes) end end diff --git a/lib/itamae/resource/file.rb b/lib/itamae/resource/file.rb index 4f6e1521..9fc253f4 100644 --- a/lib/itamae/resource/file.rb +++ b/lib/itamae/resource/file.rb @@ -138,7 +138,7 @@ def compare_file Itamae.logger.info line.chomp end end - runner.report(:file_content_changed, diff: diff.stdout) + runner.handler.event(:file_content_changed, diff: diff.stdout) end end diff --git a/lib/itamae/runner.rb b/lib/itamae/runner.rb index fe1e214e..ade3e245 100644 --- a/lib/itamae/runner.rb +++ b/lib/itamae/runner.rb @@ -30,12 +30,13 @@ def run(recipe_files, backend_type, options) attr_reader :node attr_reader :tmpdir attr_reader :children + attr_reader :handler def initialize(backend, options) @backend = backend @options = options - prepare_handlers + prepare_handler @node = create_node @tmpdir = "/tmp/itamae_tmp" @@ -81,22 +82,6 @@ def save_profile(path) end end - def report(event_name, *args) - @handers.each do |r| - r.event(event_name, *args) - end - end - - def report_with_block(event_name, *args) - report("#{event_name}_started".to_sym, *args) - yield - rescue - report("#{event_name}_failed".to_sym, *args) - raise - else - report("#{event_name}_completed".to_sym, *args) - end - private def create_node hash = {} @@ -127,13 +112,14 @@ def create_node Node.new(hash, @backend) end - def prepare_handlers - @handler = (@options[:handlers] || []).map do |handler| + def prepare_handler + @handler = HandlerProxy.new + (@options[:handlers] || []).each do |handler| type = handler.delete('type') unless type raise "#{type} field is not set" end - Handler.from_type(type).new(handler) + @handler << Handler.from_type(type).new(handler) end end end From b2ce6bbd402ff52e1743f6fe8773c39c8527d12d Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Mon, 7 Dec 2015 18:34:54 +0900 Subject: [PATCH 16/23] Add resource_updated event. --- lib/itamae/resource/base.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/itamae/resource/base.rb b/lib/itamae/resource/base.rb index ca645e3b..f3d3400f 100644 --- a/lib/itamae/resource/base.rb +++ b/lib/itamae/resource/base.rb @@ -138,7 +138,10 @@ def run(specific_action = nil) end verify unless runner.dry_run? - notify if updated? + if updated? + notify + runner.handler.event(:resource_updated) + end end @updated = false From c992a3a8bf0f884e7213ebe80efa22ff1de0dce6 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 10:07:12 +0900 Subject: [PATCH 17/23] Rename << method to register_instance. --- lib/itamae/handler_proxy.rb | 2 +- lib/itamae/runner.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/itamae/handler_proxy.rb b/lib/itamae/handler_proxy.rb index d54001a6..c8c206be 100644 --- a/lib/itamae/handler_proxy.rb +++ b/lib/itamae/handler_proxy.rb @@ -4,7 +4,7 @@ def initialize @instances = [] end - def <<(instance) + def register_instance(instance) @instances << instance end diff --git a/lib/itamae/runner.rb b/lib/itamae/runner.rb index ade3e245..84e1ff51 100644 --- a/lib/itamae/runner.rb +++ b/lib/itamae/runner.rb @@ -119,7 +119,7 @@ def prepare_handler unless type raise "#{type} field is not set" end - @handler << Handler.from_type(type).new(handler) + @handler.register_instance(Handler.from_type(type).new(handler)) end end end From 288f3bc963fdbdea2da5bcf5c556e67e8afaabe4 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 13:39:27 +0900 Subject: [PATCH 18/23] Fix specs for Resource::Base. --- spec/unit/lib/itamae/resource/base_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/unit/lib/itamae/resource/base_spec.rb b/spec/unit/lib/itamae/resource/base_spec.rb index 65da8851..8da23229 100644 --- a/spec/unit/lib/itamae/resource/base_spec.rb +++ b/spec/unit/lib/itamae/resource/base_spec.rb @@ -100,14 +100,15 @@ class TestResource < Itamae::Resource::Base describe TestResource do subject(:resource) { described_class.new(recipe, "name") } - let(:commands) { double(:commands) } + let(:handler) { Itamae::HandlerProxy.new } let(:runner) do instance_double(Itamae::Runner).tap do |r| allow(r).to receive(:dry_run?).and_return(false) + allow(r).to receive(:handler).and_return(handler) end end let(:recipe) do - double(:recipe).tap do |r| + instance_double(Itamae::Recipe).tap do |r| allow(r).to receive(:runner).and_return(runner) end end From d2d7ae6c592bf24f1e7519c5f0db97fee766ed95 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 16:03:40 +0900 Subject: [PATCH 19/23] Do not require handler/debug explicitly. --- lib/itamae/handler.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/itamae/handler.rb b/lib/itamae/handler.rb index da3ae8d4..43f30a32 100644 --- a/lib/itamae/handler.rb +++ b/lib/itamae/handler.rb @@ -1,5 +1,4 @@ require 'itamae/handler/base' -require 'itamae/handler/debug' module Itamae module Handler From 9599b3adbc6a84687a3dfacc6fecf6185d8d43bd Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 16:04:12 +0900 Subject: [PATCH 20/23] Add private method Handler::Base#hostname. --- lib/itamae/handler/base.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/itamae/handler/base.rb b/lib/itamae/handler/base.rb index 8153351c..ece4310a 100644 --- a/lib/itamae/handler/base.rb +++ b/lib/itamae/handler/base.rb @@ -1,3 +1,5 @@ +require 'socket' + module Itamae module Handler class Base @@ -25,6 +27,12 @@ def event(type, payload = {}) @actions.pop end end + + private + + def hostname + @hostname ||= @options['hostname'] || Socket.gethostname + end end end end From b625959dda23ad08b5bcae6e3f2948e248a05401 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 16:04:34 +0900 Subject: [PATCH 21/23] Add json handler. --- lib/itamae/handler/json.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 lib/itamae/handler/json.rb diff --git a/lib/itamae/handler/json.rb b/lib/itamae/handler/json.rb new file mode 100644 index 00000000..bbe6fbd4 --- /dev/null +++ b/lib/itamae/handler/json.rb @@ -0,0 +1,22 @@ +module Itamae + module Handler + class Json < Base + def initialize(*) + super + require 'time' + open_file + end + + def event(type, payload = {}) + super + @f.puts({'time' => Time.now.iso8601, 'event' => type, 'payload' => payload}.to_json) + end + + private + + def open_file + @f = open(@options.fetch('path'), 'a') + end + end + end +end From ea073f308ab38dd1453696d569ec05171fc9cb74 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 16:04:42 +0900 Subject: [PATCH 22/23] Add fluentd handler. --- itamae.gemspec | 1 + lib/itamae/handler/fluentd.rb | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 lib/itamae/handler/fluentd.rb diff --git a/itamae.gemspec b/itamae.gemspec index fa8f93a6..4c84ee34 100644 --- a/itamae.gemspec +++ b/itamae.gemspec @@ -30,4 +30,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "pry-byebug" spec.add_development_dependency "docker-api", "~> 1.20" spec.add_development_dependency "fakefs" + spec.add_development_dependency "fluent-logger" end diff --git a/lib/itamae/handler/fluentd.rb b/lib/itamae/handler/fluentd.rb new file mode 100644 index 00000000..4710b615 --- /dev/null +++ b/lib/itamae/handler/fluentd.rb @@ -0,0 +1,42 @@ +module Itamae + module Handler + class Fluentd < Base + def initialize(*) + super + load_fluent_logger + end + + def event(type, payload = {}) + super + + unless @logger.post(type, payload.merge(hostname: hostname)) + Itamae.logger.warn "Sending logs to Fluentd failed: #{@logger.last_error}" + end + end + + private + + def load_fluent_logger + begin + require 'fluent-logger' + rescue LoadError + raise "Loading fluent-logger gem failed. Please install 'fluent-logger' gem to use fluentd handler." + end + + @logger = Fluent::Logger::FluentLogger.new(tag_prefix, host: fluentd_host, port: fluentd_port) + end + + def tag_prefix + @options['tag_prefix'] || 'itamae_server' + end + + def fluentd_host + @options['host'] || 'localhost' + end + + def fluentd_port + (@options['port'] || 24224).to_i + end + end + end +end From e9d8428505c1839797cb415d9ac3adc829c43b60 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Tue, 8 Dec 2015 16:26:14 +0900 Subject: [PATCH 23/23] Add specs for handlers. --- lib/itamae/handler/base.rb | 2 ++ lib/itamae/handler/fluentd.rb | 8 +++-- spec/unit/lib/itamae/handler/base_spec.rb | 34 ++++++++++++++++++ spec/unit/lib/itamae/handler/fluentd_spec.rb | 19 ++++++++++ spec/unit/lib/itamae/handler_proxy_spec.rb | 38 ++++++++++++++++++++ spec/unit/lib/itamae/handler_spec.rb | 11 ++++++ 6 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 spec/unit/lib/itamae/handler/base_spec.rb create mode 100644 spec/unit/lib/itamae/handler/fluentd_spec.rb create mode 100644 spec/unit/lib/itamae/handler_proxy_spec.rb create mode 100644 spec/unit/lib/itamae/handler_spec.rb diff --git a/lib/itamae/handler/base.rb b/lib/itamae/handler/base.rb index ece4310a..86c9c868 100644 --- a/lib/itamae/handler/base.rb +++ b/lib/itamae/handler/base.rb @@ -3,6 +3,8 @@ module Itamae module Handler class Base + attr_reader :recipes, :resources, :actions + def initialize(options) @options = options diff --git a/lib/itamae/handler/fluentd.rb b/lib/itamae/handler/fluentd.rb index 4710b615..5d78b08c 100644 --- a/lib/itamae/handler/fluentd.rb +++ b/lib/itamae/handler/fluentd.rb @@ -1,6 +1,8 @@ module Itamae module Handler class Fluentd < Base + attr_accessor :fluent_logger # for test + def initialize(*) super load_fluent_logger @@ -9,8 +11,8 @@ def initialize(*) def event(type, payload = {}) super - unless @logger.post(type, payload.merge(hostname: hostname)) - Itamae.logger.warn "Sending logs to Fluentd failed: #{@logger.last_error}" + unless @fluent_logger.post(type, payload.merge(hostname: hostname)) + Itamae.logger.warn "Sending logs to Fluentd failed: #{@fluent_logger.last_error}" end end @@ -23,7 +25,7 @@ def load_fluent_logger raise "Loading fluent-logger gem failed. Please install 'fluent-logger' gem to use fluentd handler." end - @logger = Fluent::Logger::FluentLogger.new(tag_prefix, host: fluentd_host, port: fluentd_port) + @fluent_logger = Fluent::Logger::FluentLogger.new(tag_prefix, host: fluentd_host, port: fluentd_port) end def tag_prefix diff --git a/spec/unit/lib/itamae/handler/base_spec.rb b/spec/unit/lib/itamae/handler/base_spec.rb new file mode 100644 index 00000000..e24e4192 --- /dev/null +++ b/spec/unit/lib/itamae/handler/base_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Itamae::Handler::Base do + subject(:handler) { described_class.new({}) } + + context "when receiving recipe_started event" do + it "stores the payload" do + subject.event(:recipe_started, :payload) + expect(subject.recipes).to eq([:payload]) + end + end + + context "when receiving recipe_completed event" do + before do + subject.event(:recipe_started, :payload) + end + + it "pops the payload" do + subject.event(:recipe_completed, :payload) + expect(subject.recipes).to eq([]) + end + end + + context "when receiving recipe_failed event" do + before do + subject.event(:recipe_started, :payload) + end + + it "pops the payload" do + subject.event(:recipe_failed, :payload) + expect(subject.recipes).to eq([]) + end + end +end diff --git a/spec/unit/lib/itamae/handler/fluentd_spec.rb b/spec/unit/lib/itamae/handler/fluentd_spec.rb new file mode 100644 index 00000000..9b2a4a0f --- /dev/null +++ b/spec/unit/lib/itamae/handler/fluentd_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' +require 'itamae/handler/fluentd' + +describe Itamae::Handler::Fluentd do + subject(:handler) do + described_class.new(options).tap do |h| + h.fluent_logger = fluent_logger + end + end + let(:options) { {'hostname' => 'me'} } + let(:fluent_logger) { Fluent::Logger::TestLogger.new } + + describe '#event' do + it 'posts a record to fluent logger' do + subject.event(:type, {arg: 'value'}) + expect(fluent_logger.queue).to eq([{arg: 'value', hostname: 'me'}]) + end + end +end diff --git a/spec/unit/lib/itamae/handler_proxy_spec.rb b/spec/unit/lib/itamae/handler_proxy_spec.rb new file mode 100644 index 00000000..48dfcef3 --- /dev/null +++ b/spec/unit/lib/itamae/handler_proxy_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +module Itamae + describe HandlerProxy do + let(:handler) { instance_double(Handler::Base) } + before { subject.register_instance(handler) } + + describe "#event" do + context "with block" do + context "when the block completes" do + it "fires *_started and *_completed events" do + expect(handler).to receive(:event).with(:name_started, :arg) + expect(handler).to receive(:event).with(:name_completed, :arg) + subject.event(:name, :arg) { } + end + end + + context "when the block fails" do + it "fires *_started and *_failed events" do + expect(handler).to receive(:event).with(:name_started, :arg) + expect(handler).to receive(:event).with(:name_failed, :arg) + expect { + subject.event(:name, :arg) { raise } + }.to raise_error + end + end + end + + context "without block" do + it "fires the event" do + expect(handler).to receive(:event).with(:name, :arg) + subject.event(:name, :arg) + end + end + end + end +end + diff --git a/spec/unit/lib/itamae/handler_spec.rb b/spec/unit/lib/itamae/handler_spec.rb new file mode 100644 index 00000000..830c3d40 --- /dev/null +++ b/spec/unit/lib/itamae/handler_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +module Itamae + describe Handler do + describe ".from_type" do + it "returns handler class" do + expect(described_class.from_type('debug')).to eq(Handler::Debug) + end + end + end +end