itamae-mitsurin 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE.txt +26 -0
  6. data/README.md +44 -0
  7. data/Rakefile +55 -0
  8. data/bin/itamae +5 -0
  9. data/bin/itamae-mitsurin +5 -0
  10. data/itamae-mitsurin.gemspec +35 -0
  11. data/lib/itamae.rb +18 -0
  12. data/lib/itamae/backend.rb +293 -0
  13. data/lib/itamae/cli.rb +86 -0
  14. data/lib/itamae/definition.rb +40 -0
  15. data/lib/itamae/ext.rb +1 -0
  16. data/lib/itamae/ext/specinfra.rb +39 -0
  17. data/lib/itamae/generators.rb +20 -0
  18. data/lib/itamae/generators/cookbook.rb +22 -0
  19. data/lib/itamae/generators/project.rb +22 -0
  20. data/lib/itamae/generators/role.rb +22 -0
  21. data/lib/itamae/generators/templates/cookbook/default.rb +0 -0
  22. data/lib/itamae/generators/templates/cookbook/files/.keep +0 -0
  23. data/lib/itamae/generators/templates/cookbook/templates/.keep +0 -0
  24. data/lib/itamae/generators/templates/project/Gemfile +4 -0
  25. data/lib/itamae/generators/templates/project/cookbooks/.keep +0 -0
  26. data/lib/itamae/generators/templates/project/roles/.keep +0 -0
  27. data/lib/itamae/generators/templates/role/default.rb +0 -0
  28. data/lib/itamae/generators/templates/role/files/.keep +0 -0
  29. data/lib/itamae/generators/templates/role/templates/.keep +0 -0
  30. data/lib/itamae/handler.rb +21 -0
  31. data/lib/itamae/handler/base.rb +40 -0
  32. data/lib/itamae/handler/debug.rb +10 -0
  33. data/lib/itamae/handler/fluentd.rb +44 -0
  34. data/lib/itamae/handler/json.rb +22 -0
  35. data/lib/itamae/handler_proxy.rb +38 -0
  36. data/lib/itamae/logger.rb +124 -0
  37. data/lib/itamae/mitsurin.rb +13 -0
  38. data/lib/itamae/mitsurin/cli.rb +56 -0
  39. data/lib/itamae/mitsurin/creators.rb +19 -0
  40. data/lib/itamae/mitsurin/creators/cookbook.rb +24 -0
  41. data/lib/itamae/mitsurin/creators/project.rb +24 -0
  42. data/lib/itamae/mitsurin/creators/templates/project/.rspec +2 -0
  43. data/lib/itamae/mitsurin/creators/templates/project/Gemfile +3 -0
  44. data/lib/itamae/mitsurin/creators/templates/project/Rakefile +2 -0
  45. data/lib/itamae/mitsurin/creators/templates/project/environments/.keep +0 -0
  46. data/lib/itamae/mitsurin/creators/templates/project/environments/sample.json +7 -0
  47. data/lib/itamae/mitsurin/creators/templates/project/nodes/.keep +0 -0
  48. data/lib/itamae/mitsurin/creators/templates/project/nodes/sample01.json +8 -0
  49. data/lib/itamae/mitsurin/creators/templates/project/roles/.keep +0 -0
  50. data/lib/itamae/mitsurin/creators/templates/project/site-cookbooks/_base/_base/attributes/.keep +0 -0
  51. data/lib/itamae/mitsurin/creators/templates/project/site-cookbooks/_base/_base/files/.keep +0 -0
  52. data/lib/itamae/mitsurin/creators/templates/project/site-cookbooks/_base/_base/recipes/default.rb +0 -0
  53. data/lib/itamae/mitsurin/creators/templates/project/site-cookbooks/_base/_base/spec/default_spec.rb +2 -0
  54. data/lib/itamae/mitsurin/creators/templates/project/site-cookbooks/_base/_base/templates/.keep +0 -0
  55. data/lib/itamae/mitsurin/creators/templates/project/spec/spec_helper.rb +32 -0
  56. data/lib/itamae/mitsurin/creators/templates/project/tmp-nodes/.keep +0 -0
  57. data/lib/itamae/mitsurin/creators/templates/site-cookbooks/attributes/.keep +0 -0
  58. data/lib/itamae/mitsurin/creators/templates/site-cookbooks/files/.keep +0 -0
  59. data/lib/itamae/mitsurin/creators/templates/site-cookbooks/recipes/default.rb +0 -0
  60. data/lib/itamae/mitsurin/creators/templates/site-cookbooks/spec/.keep +0 -0
  61. data/lib/itamae/mitsurin/creators/templates/site-cookbooks/templates/.keep +0 -0
  62. data/lib/itamae/mitsurin/itamae_task.rb +199 -0
  63. data/lib/itamae/mitsurin/serverspec_task.rb +110 -0
  64. data/lib/itamae/mitsurin/version.rb +5 -0
  65. data/lib/itamae/mitsurin/version.txt +1 -0
  66. data/lib/itamae/node.rb +74 -0
  67. data/lib/itamae/notification.rb +46 -0
  68. data/lib/itamae/recipe.rb +171 -0
  69. data/lib/itamae/recipe_children.rb +86 -0
  70. data/lib/itamae/resource.rb +73 -0
  71. data/lib/itamae/resource/aws_ebs_volume.rb +84 -0
  72. data/lib/itamae/resource/base.rb +374 -0
  73. data/lib/itamae/resource/directory.rb +63 -0
  74. data/lib/itamae/resource/execute.rb +26 -0
  75. data/lib/itamae/resource/file.rb +176 -0
  76. data/lib/itamae/resource/gem_package.rb +81 -0
  77. data/lib/itamae/resource/git.rb +94 -0
  78. data/lib/itamae/resource/group.rb +42 -0
  79. data/lib/itamae/resource/http_request.rb +71 -0
  80. data/lib/itamae/resource/link.rb +33 -0
  81. data/lib/itamae/resource/local_ruby_block.rb +15 -0
  82. data/lib/itamae/resource/package.rb +44 -0
  83. data/lib/itamae/resource/remote_directory.rb +84 -0
  84. data/lib/itamae/resource/remote_file.rb +54 -0
  85. data/lib/itamae/resource/service.rb +69 -0
  86. data/lib/itamae/resource/template.rb +53 -0
  87. data/lib/itamae/resource/user.rb +93 -0
  88. data/lib/itamae/runner.rb +124 -0
  89. data/spec/integration/Vagrantfile +35 -0
  90. data/spec/integration/default_spec.rb +226 -0
  91. data/spec/integration/recipes/default.rb +423 -0
  92. data/spec/integration/recipes/default2.rb +6 -0
  93. data/spec/integration/recipes/define/default.rb +6 -0
  94. data/spec/integration/recipes/define/files/remote_file_in_definition +1 -0
  95. data/spec/integration/recipes/dry_run.rb +6 -0
  96. data/spec/integration/recipes/files/remote_file_auto +1 -0
  97. data/spec/integration/recipes/hello.erb +6 -0
  98. data/spec/integration/recipes/hello.txt +1 -0
  99. data/spec/integration/recipes/included.rb +9 -0
  100. data/spec/integration/recipes/node.json +3 -0
  101. data/spec/integration/recipes/redefine.rb +20 -0
  102. data/spec/integration/recipes/templates/template_auto.erb +6 -0
  103. data/spec/integration/spec_helper.rb +42 -0
  104. data/spec/unit/lib/itamae/backend_spec.rb +95 -0
  105. data/spec/unit/lib/itamae/handler/base_spec.rb +34 -0
  106. data/spec/unit/lib/itamae/handler/fluentd_spec.rb +19 -0
  107. data/spec/unit/lib/itamae/handler_proxy_spec.rb +38 -0
  108. data/spec/unit/lib/itamae/handler_spec.rb +11 -0
  109. data/spec/unit/lib/itamae/node_spec.rb +14 -0
  110. data/spec/unit/lib/itamae/recipe_spec.rb +6 -0
  111. data/spec/unit/lib/itamae/resource/base_spec.rb +127 -0
  112. data/spec/unit/lib/itamae/resource_spec.rb +23 -0
  113. data/spec/unit/lib/itamae/runner_spec.rb +32 -0
  114. data/spec/unit/spec_helper.rb +23 -0
  115. metadata +393 -0
@@ -0,0 +1,124 @@
1
+ require 'itamae'
2
+ require 'logger'
3
+ require 'ansi/code'
4
+
5
+ module Itamae
6
+ module Logger
7
+ module Helper
8
+ def with_indent
9
+ indent
10
+ yield
11
+ ensure
12
+ outdent
13
+ end
14
+
15
+ def with_indent_if(condition, &block)
16
+ if condition
17
+ with_indent(&block)
18
+ else
19
+ block.call
20
+ end
21
+ end
22
+
23
+ def indent
24
+ self.indent_depth += 1
25
+ end
26
+
27
+ def outdent
28
+ self.indent_depth -= 1
29
+ self.indent_depth = 0 if self.indent_depth < 0
30
+ end
31
+
32
+ def indent_depth
33
+ @indent_depth ||= 0
34
+ end
35
+
36
+ def indent_depth=(val)
37
+ @indent_depth = val
38
+ end
39
+
40
+ def color(code, &block)
41
+ if self.formatter.respond_to?(:color)
42
+ self.formatter.color(code, &block)
43
+ else
44
+ block.call
45
+ end
46
+ end
47
+
48
+ %w!debug info warn error fatal unknown!.each do |level|
49
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
50
+ def #{level}(msg)
51
+ super(" " * indent_depth + msg)
52
+ end
53
+ EOC
54
+ end
55
+ end
56
+
57
+ class Formatter
58
+ attr_accessor :colored
59
+
60
+ def call(severity, datetime, progname, msg)
61
+ log = "%s : %s\n" % ["%5s" % severity, msg2str(msg)]
62
+ if colored
63
+ colorize(log, severity)
64
+ else
65
+ log
66
+ end
67
+ end
68
+
69
+ def color(code)
70
+ prev_color = @color
71
+ @color = code
72
+ yield
73
+ ensure
74
+ @color = prev_color
75
+ end
76
+
77
+ private
78
+
79
+ def msg2str(msg)
80
+ case msg
81
+ when ::String
82
+ msg
83
+ when ::Exception
84
+ "#{ msg.message } (#{ msg.class })\n" <<
85
+ (msg.backtrace || []).join("\n")
86
+ else
87
+ msg.inspect
88
+ end
89
+ end
90
+
91
+ def colorize(str, severity)
92
+ if @color
93
+ color_code = @color
94
+ else
95
+ color_code = case severity
96
+ when "INFO"
97
+ :clear
98
+ when "WARN"
99
+ :magenta
100
+ when "ERROR"
101
+ :red
102
+ else
103
+ :clear
104
+ end
105
+ end
106
+ ANSI.public_send(color_code) { str }
107
+ end
108
+ end
109
+ end
110
+
111
+ @logger = ::Logger.new($stdout).tap do |l|
112
+ l.formatter = Itamae::Logger::Formatter.new
113
+ end.extend(Itamae::Logger::Helper)
114
+
115
+ class << self
116
+ def logger
117
+ @logger
118
+ end
119
+
120
+ def logger=(l)
121
+ @logger = l.extend(Itamae::Logger::Helper)
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,13 @@
1
+ require 'itamae/mitsurin/version'
2
+ require 'itamae/mitsurin/cli'
3
+ require 'itamae/mitsurin/creators'
4
+ #require 'itamae/mitsurin/itamae_task'
5
+ #require 'itamae/mitsurin/serverspec_task'
6
+ require 'aws-sdk'
7
+
8
+
9
+ module Itamae
10
+ module Mitsurin
11
+ # TODO
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ require 'itamae'
2
+ require 'itamae/mitsurin'
3
+ require 'thor'
4
+
5
+ module Itamae
6
+ module Mitsurin
7
+ class CLI < Thor
8
+ CREATE_TARGETS = %w[ cookbook ].freeze
9
+
10
+ class_option :with_git, type: :string, aliases: ['-g']
11
+
12
+ desc "version", "Print version"
13
+ def version
14
+ puts "Itamae-Mitsurin v#{Itamae::Mitsurin::VERSION}"
15
+ end
16
+
17
+ desc "init [NAME]", "Create a new project"
18
+ def init(name)
19
+ creator = Creators::Project.new
20
+ creator.destination_root = name
21
+ creator.invoke_all
22
+ end
23
+
24
+ desc 'create cookbook [LAYER] [NAME]', 'Initialize cookbook (short-cut alias: "c")'
25
+ map 'c' => 'create'
26
+ def create(target, layer, name)
27
+ name = layer + '/' + name
28
+ validate_create_target!('create', target)
29
+
30
+ creator = Creators.find(target).new
31
+ creator.destination_root = File.join("site-cookbooks", name)
32
+ creator.copy_files
33
+ end
34
+
35
+ desc 'destroy cookbook [LAYER] [NAME]', 'Undo cookbook (short-cut alias: "d")'
36
+ map 'd' => 'destroy'
37
+ def destroy(target, layer, name)
38
+ name = layer + '/' + name
39
+ validate_create_target!('destroy', target)
40
+
41
+ creator = Creators.find(target).new
42
+ creator.destination_root = File.join("site-cookbooks", name)
43
+ creator.remove_files
44
+ end
45
+
46
+ private
47
+ def validate_create_target!(command, target)
48
+ unless CREATE_TARGETS.include?(target)
49
+ msg = %Q!ERROR: "itamae #{command}" was called with "#{target}" !
50
+ msg << "but expected to be in #{CREATE_TARGETS.inspect}"
51
+ fail InvocationError, msg
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,19 @@
1
+ require "itamae/mitsurin/creators/cookbook"
2
+ require "itamae/mitsurin/creators/project"
3
+
4
+ module Itamae
5
+ module Mitsurin
6
+ module Creators
7
+ def self.find(target)
8
+ case target
9
+ when 'cookbook'
10
+ Cookbook
11
+ when 'project'
12
+ Project
13
+ else
14
+ raise "unexpected target: #{target}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+
4
+ module Itamae
5
+ module Mitsurin
6
+ module Creators
7
+ class Cookbook < Thor::Group
8
+ include Thor::Actions
9
+
10
+ def self.source_root
11
+ File.expand_path('../templates/site-cookbooks', __FILE__)
12
+ end
13
+
14
+ def copy_files
15
+ directory '.'
16
+ end
17
+
18
+ def remove_files
19
+ remove_file '.'
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+
4
+ module Itamae
5
+ module Mitsurin
6
+ module Creators
7
+ class Project < Thor::Group
8
+ include Thor::Actions
9
+
10
+ def self.source_root
11
+ File.dirname(__FILE__) + '/templates/project'
12
+ end
13
+
14
+ def copy_files
15
+ directory '.'
16
+ end
17
+
18
+ def bundle
19
+ run 'bundle install'
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'itamae-mitsurin'
@@ -0,0 +1,2 @@
1
+ require 'itamae/mitsurin/itamae_task'
2
+ require 'itamae/mitsurin/serverspec_task'
@@ -0,0 +1,7 @@
1
+ {
2
+ "environments": {
3
+ "ssh_port": "22",
4
+ "ssh_user": "ec2-user",
5
+ "ssh_key": "keipair.pem"
6
+ }
7
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "run_list": [
3
+ "recipe[_base]"
4
+ ],
5
+ "environments": {
6
+ "hostname": "sample01.localhost"
7
+ }
8
+ }
@@ -0,0 +1,32 @@
1
+ require 'serverspec'
2
+ require 'net/ssh'
3
+ require 'specinfra/helper/set'
4
+ require 'json'
5
+ include Specinfra::Helper::Set
6
+
7
+ set :backend, :ssh
8
+
9
+ if ENV['ASK_SUDO_PASSWORD']
10
+ begin
11
+ require 'highline/import'
12
+ rescue LoadError
13
+ fail "highline is not available. Try installing it."
14
+ end
15
+ set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false }
16
+ else
17
+ set :sudo_password, ENV['SUDO_PASSWORD']
18
+ end
19
+
20
+ host = ENV['TARGET_HOST']
21
+ node_file = ENV['NODE_FILE']
22
+ attributes = JSON.parse(File.read(node_file), symbolize_names: true)
23
+ set_property attributes
24
+
25
+ options = Net::SSH::Config.for(host)
26
+ options[:user] ||= Etc.getlogin
27
+ options[:password] = ENV['SSH_PASSWORD']
28
+ options[:keys] = ENV['SSH_KEY']
29
+
30
+ set :host, options[:host_name] || host
31
+ set :shell, '/bin/bash'
32
+ set :ssh_options, options
@@ -0,0 +1,199 @@
1
+ require 'rake'
2
+ require 'json'
3
+ require 'simple_color'
4
+ include Rake::DSL if defined? Rake::DSL
5
+
6
+ module Itamae
7
+ module Mitsurin
8
+ class ItamaeTask
9
+
10
+ class << self
11
+
12
+ class ::Hash
13
+ def deep_merge(other)
14
+ merger = lambda {|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2}
15
+ self.merge(other, &merger)
16
+ end
17
+
18
+ def deep_merge!(other)
19
+ merger = lambda {|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2}
20
+ self.merge!(other, &merger)
21
+ end
22
+ end
23
+
24
+ def self.get_roles(node_file)
25
+ roles = []
26
+ JSON.parse(File.read(node_file))['run_list'].each do |role|
27
+ roles << role.gsub(/role\[(.+)\]/, '\1') if /role\[(.+)\]/ === role
28
+ end
29
+ roles
30
+ end
31
+
32
+ def self.get_recipes(role)
33
+ recipes = []
34
+ JSON.parse(File.read("roles/#{role}.json"))['run_list'].each do |recipe|
35
+ if /recipe\[(.+)::(.+)\]/ === recipe
36
+ recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
37
+ else
38
+ recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil}
39
+ end
40
+ end
41
+ recipes
42
+ end
43
+
44
+ def self.get_node_recipes(node_file)
45
+ recipes = []
46
+ JSON.parse(File.read(node_file))['run_list'].each do |recipe|
47
+ if /recipe\[(.+)::(.+)\]/ === recipe
48
+ recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
49
+ else
50
+ recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil} unless /role\[(.+)\]/ === recipe
51
+ end
52
+ end
53
+ recipes
54
+ end
55
+
56
+ def self.jq(*objs)
57
+ par = nil
58
+ objs.each {|obj| par = JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)}
59
+ return par
60
+ end
61
+
62
+ def self.write_json(filename)
63
+ File.open "tmp-nodes/#{filename}.json", 'w' do |f|
64
+ f.flock File::LOCK_EX
65
+ yield f
66
+ f.flock File::LOCK_UN
67
+ end
68
+ end
69
+
70
+ color = SimpleColor.new
71
+
72
+ namespace :itamae do
73
+ Dir.glob("nodes/**/*.json").each do |node_file|
74
+
75
+ bname = File.basename(node_file, '.json')
76
+ node_h = JSON.parse(File.read(node_file), symbolize_names: true)
77
+ desc "Run to #{bname}"
78
+
79
+ task node_h[:environments][:hostname].split(".")[0] do
80
+ begin
81
+ recipes = []
82
+ get_roles(node_file).each do |role|
83
+ recipes << get_recipes(role)
84
+ end
85
+ get_node_recipes(node_file).each do |recipe|
86
+ recipes << recipe
87
+ end
88
+ rescue Exception => e
89
+ puts e.class.to_s + ", " + e.backtrace[0].to_s
90
+ puts "nodefile or role error, nodefile:#{node_file} reason:#{e.message}"
91
+ exit 1
92
+ else
93
+ recipes.flatten!
94
+ end
95
+
96
+ # get env attr
97
+ begin
98
+ env_set = node_h[:environments][:set]
99
+ env_h = JSON.parse(File.read("environments/#{env_set}.json"), symbolize_names: true)
100
+ rescue Exception => e
101
+ puts e.class.to_s + ", " + e.backtrace[0].to_s
102
+ puts "nodefile or environments error, nodefile:#{node_file} reason:#{e.message}"
103
+ exit 1
104
+ end
105
+
106
+ # get recipe attr
107
+ recipe_attr_file = []
108
+ recipes.each do |recipe_h|
109
+ if recipe_h["#{recipe_h.keys.join}"].nil?
110
+ recipe_attr_file.insert 0,
111
+ Dir.glob("site-cookbooks/**/#{recipe_h.keys.join}/attributes/default.json")
112
+ else
113
+ recipe_attr_file <<
114
+ Dir.glob("site-cookbooks/**/#{recipe_h.keys.join}/attributes/#{recipe_h["#{recipe_h.keys.join}"]}.json")
115
+ end
116
+ end
117
+
118
+ recipe_attr_file.flatten!
119
+
120
+ # recipe attr other=env
121
+ recipe_env_h_a = []
122
+ recipe_attr_file.each do |file|
123
+ recipe_h = JSON.parse(File.read(file), symbolize_names: true)
124
+ recipe_env_h_a << recipe_h.deep_merge(env_h)
125
+ end
126
+
127
+ # recipe attr other=recipes
128
+ moto = recipe_env_h_a[0]
129
+ recipe_env_h_a.each {|hash| moto.deep_merge!(hash)}
130
+ recipe_env_h = moto
131
+
132
+ if recipe_env_h.nil?
133
+ # node attr other=env
134
+ node_env_h = env_h.deep_merge(node_h)
135
+ node_env_j = jq node_env_h
136
+ write_json(bname) {|file| file.puts node_env_j}
137
+ else
138
+ # node attr other=recipe_env
139
+ recipe_env_node_h = recipe_env_h.deep_merge(node_h)
140
+ recipe_env_node_j = jq recipe_env_node_h
141
+ write_json(bname) {|file| file.puts recipe_env_node_j}
142
+ end
143
+
144
+ recipes << {'_base' => nil}
145
+ node_property = JSON.parse(File.read("tmp-nodes/#{bname}.json"), symbolize_names: true)
146
+ node = node_property[:environments][:hostname]
147
+ ssh_user = node_property[:environments][:ssh_user]
148
+ ssh_password = node_property[:environments][:ssh_password]
149
+ ssh_port = node_property[:environments][:ssh_port]
150
+ ssh_key = node_property[:environments][:ssh_key]
151
+
152
+ ENV['TARGET_HOST'] = node
153
+ ENV['NODE_FILE'] = node_file
154
+ ENV['SSH_PASSWORD'] = ssh_password
155
+
156
+ command = "bundle exec itamae ssh"
157
+ command << " -h #{node}"
158
+ command << " -u #{ssh_user}"
159
+ command << " -p #{ssh_port}"
160
+ command << " -i keys/#{ssh_key}" unless ssh_key.nil?
161
+ command << " -j tmp-nodes/#{bname}.json"
162
+ command << " --shell=bash"
163
+ command << " --ask-password" unless ssh_password.nil?
164
+ command << " --dry-run" if ENV['dry_run'] == "true"
165
+ command << " -l debug" if ENV['debug'] == "true"
166
+
167
+ # recipe load to_command
168
+ command_recipe = []
169
+ recipes.each do |recipe_h|
170
+ if recipe_h["#{recipe_h.keys.join}"].nil?
171
+ command_recipe <<
172
+ " #{Dir.glob("site-cookbooks/**/#{recipe_h.keys.join}/recipes/default.rb").join}"
173
+ else
174
+ command_recipe <<
175
+ " #{Dir.glob("site-cookbooks/**/#{recipe_h.keys.join}/recipes/#{recipe_h["#{recipe_h.keys.join}"]}.rb").join}"
176
+ end
177
+ end
178
+ command_recipe.sort_by! {|item| File.dirname(item)}
179
+ command << command_recipe.join
180
+
181
+ color.echos(:red ,%!Run Itamae to \"#{bname}\"!)
182
+ color.echos(:blue, %!Set Roles to \"#{get_roles(node_file).join(", ")}\"!)
183
+ run_list_noti = []
184
+ command_recipe.each {|c_recipe| run_list_noti << c_recipe.split("/") [2]}
185
+ color.echos(:green, %!Run List to \"#{run_list_noti.uniq.join(", ")}\"!)
186
+ puts color.echos(:white, %!#{command}!)
187
+ stat = system command
188
+ if ! stat then
189
+ exit(false)
190
+ end
191
+ end
192
+
193
+ end
194
+ end
195
+
196
+ end
197
+ end
198
+ end
199
+ end