itamae-mitsurin 0.50 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +5 -5
  2. data/lib/itamae-mitsurin/cli.rb +0 -2
  3. data/lib/itamae-mitsurin/logger.rb +74 -20
  4. data/lib/itamae-mitsurin/mitsurin/base.rb +109 -0
  5. data/lib/itamae-mitsurin/mitsurin/base_task.rb +147 -0
  6. data/lib/itamae-mitsurin/mitsurin/creators/templates/project/site-cookbooks/_base/_base/recipes/default.rb +0 -11
  7. data/lib/itamae-mitsurin/mitsurin/itamae_task.rb +44 -130
  8. data/lib/itamae-mitsurin/mitsurin/itamae_with_target_task.rb +64 -157
  9. data/lib/itamae-mitsurin/mitsurin/local_task.rb +57 -131
  10. data/lib/itamae-mitsurin/mitsurin/serverspec_task.rb +56 -81
  11. data/lib/itamae-mitsurin/mitsurin/serverspec_with_target_task.rb +80 -143
  12. data/lib/itamae-mitsurin/node.rb +0 -1
  13. data/lib/itamae-mitsurin/notification.rb +0 -1
  14. data/lib/itamae-mitsurin/recipe.rb +2 -5
  15. data/lib/itamae-mitsurin/resource.rb +1 -1
  16. data/lib/itamae-mitsurin/resource/base.rb +0 -12
  17. data/lib/itamae-mitsurin/resource/http_request.rb +23 -8
  18. data/lib/itamae-mitsurin/resource/s3_file.rb +33 -0
  19. data/lib/itamae-mitsurin/runner.rb +4 -5
  20. data/lib/itamae-mitsurin/version.txt +1 -1
  21. metadata +6 -221
  22. data/lib/itamae-mitsurin/mitsurin/itamae_with_git_task.rb +0 -159
  23. data/lib/itamae-mitsurin/mitsurin/task_base.rb +0 -100
  24. data/test/test_itamae-mitsurin.rb +0 -18
  25. data/test/test_itamae-mitsurin/ext/test_specinfra.rb +0 -39
  26. data/test/test_itamae-mitsurin/handler/test_base.rb +0 -40
  27. data/test/test_itamae-mitsurin/handler/test_debug.rb +0 -10
  28. data/test/test_itamae-mitsurin/handler/test_fluentd.rb +0 -44
  29. data/test/test_itamae-mitsurin/handler/test_json.rb +0 -22
  30. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/.rspec +0 -2
  31. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/Gemfile +0 -3
  32. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/Rakefile +0 -2
  33. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/environments/.keep +0 -0
  34. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/environments/sample.json +0 -7
  35. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/keys/.keep +0 -0
  36. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/nodes/.keep +0 -0
  37. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/nodes/sample01.json +0 -9
  38. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/roles/.keep +0 -0
  39. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/site-cookbooks/_base/_base/attributes/.keep +0 -0
  40. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/site-cookbooks/_base/_base/files/.keep +0 -0
  41. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/site-cookbooks/_base/_base/recipes/default.rb +0 -1
  42. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/site-cookbooks/_base/_base/spec/default_spec.rb +0 -1
  43. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/site-cookbooks/_base/_base/templates/.keep +0 -0
  44. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/spec/spec_helper.rb +0 -33
  45. data/test/test_itamae-mitsurin/mitsurin/creators/templates/project/tmp-nodes/.keep +0 -0
  46. data/test/test_itamae-mitsurin/mitsurin/creators/templates/site-cookbooks/attributes/.keep +0 -0
  47. data/test/test_itamae-mitsurin/mitsurin/creators/templates/site-cookbooks/files/.keep +0 -0
  48. data/test/test_itamae-mitsurin/mitsurin/creators/templates/site-cookbooks/recipes/default.rb +0 -0
  49. data/test/test_itamae-mitsurin/mitsurin/creators/templates/site-cookbooks/spec/.keep +0 -0
  50. data/test/test_itamae-mitsurin/mitsurin/creators/templates/site-cookbooks/templates/.keep +0 -0
  51. data/test/test_itamae-mitsurin/mitsurin/creators/test_cookbook.rb +0 -24
  52. data/test/test_itamae-mitsurin/mitsurin/creators/test_project.rb +0 -24
  53. data/test/test_itamae-mitsurin/mitsurin/test_cli.rb +0 -56
  54. data/test/test_itamae-mitsurin/mitsurin/test_creators.rb +0 -19
  55. data/test/test_itamae-mitsurin/mitsurin/test_itamae_task.rb +0 -197
  56. data/test/test_itamae-mitsurin/mitsurin/test_itamae_with_git_task.rb +0 -213
  57. data/test/test_itamae-mitsurin/mitsurin/test_serverspec_task.rb +0 -123
  58. data/test/test_itamae-mitsurin/resource/test_aws_ebs_volume.rb +0 -84
  59. data/test/test_itamae-mitsurin/resource/test_base.rb +0 -374
  60. data/test/test_itamae-mitsurin/resource/test_directory.rb +0 -63
  61. data/test/test_itamae-mitsurin/resource/test_execute.rb +0 -26
  62. data/test/test_itamae-mitsurin/resource/test_file.rb +0 -176
  63. data/test/test_itamae-mitsurin/resource/test_gem_package.rb +0 -81
  64. data/test/test_itamae-mitsurin/resource/test_git.rb +0 -94
  65. data/test/test_itamae-mitsurin/resource/test_group.rb +0 -42
  66. data/test/test_itamae-mitsurin/resource/test_http_request.rb +0 -71
  67. data/test/test_itamae-mitsurin/resource/test_link.rb +0 -33
  68. data/test/test_itamae-mitsurin/resource/test_local_ruby_block.rb +0 -15
  69. data/test/test_itamae-mitsurin/resource/test_package.rb +0 -44
  70. data/test/test_itamae-mitsurin/resource/test_remote_directory.rb +0 -84
  71. data/test/test_itamae-mitsurin/resource/test_remote_file.rb +0 -54
  72. data/test/test_itamae-mitsurin/resource/test_service.rb +0 -69
  73. data/test/test_itamae-mitsurin/resource/test_template.rb +0 -53
  74. data/test/test_itamae-mitsurin/resource/test_user.rb +0 -93
  75. data/test/test_itamae-mitsurin/test_backend.rb +0 -297
  76. data/test/test_itamae-mitsurin/test_cli.rb +0 -88
  77. data/test/test_itamae-mitsurin/test_definition.rb +0 -40
  78. data/test/test_itamae-mitsurin/test_ext.rb +0 -1
  79. data/test/test_itamae-mitsurin/test_handler.rb +0 -21
  80. data/test/test_itamae-mitsurin/test_handler_proxy.rb +0 -38
  81. data/test/test_itamae-mitsurin/test_logger.rb +0 -124
  82. data/test/test_itamae-mitsurin/test_mitsurin.rb +0 -14
  83. data/test/test_itamae-mitsurin/test_node.rb +0 -74
  84. data/test/test_itamae-mitsurin/test_notification.rb +0 -46
  85. data/test/test_itamae-mitsurin/test_recipe.rb +0 -171
  86. data/test/test_itamae-mitsurin/test_recipe_children.rb +0 -86
  87. data/test/test_itamae-mitsurin/test_resource.rb +0 -73
  88. data/test/test_itamae-mitsurin/test_runner.rb +0 -124
  89. data/test/test_itamae-mitsurin/test_version.rb +0 -3
  90. data/test/test_itamae-mitsurin/version.txt +0 -1
  91. data/test_project/.rspec +0 -2
  92. data/test_project/Gemfile +0 -4
  93. data/test_project/Rakefile +0 -3
  94. data/test_project/environments/.keep +0 -0
  95. data/test_project/keys/.keep +0 -0
  96. data/test_project/nodes/.keep +0 -0
  97. data/test_project/nodes/test.json +0 -9
  98. data/test_project/roles/.keep +0 -0
  99. data/test_project/roles/test.json +0 -14
  100. data/test_project/site-cookbooks/_base/_base/attributes/.keep +0 -0
  101. data/test_project/site-cookbooks/_base/_base/files/.keep +0 -0
  102. data/test_project/site-cookbooks/_base/_base/recipes/default.rb +0 -1
  103. data/test_project/site-cookbooks/_base/_base/spec/default_spec.rb +0 -1
  104. data/test_project/site-cookbooks/_base/_base/templates/.keep +0 -0
  105. data/test_project/site-cookbooks/a_test/directory/attributes/.keep +0 -0
  106. data/test_project/site-cookbooks/a_test/directory/files/.keep +0 -0
  107. data/test_project/site-cookbooks/a_test/directory/recipes/default.rb +0 -8
  108. data/test_project/site-cookbooks/a_test/directory/spec/.keep +0 -0
  109. data/test_project/site-cookbooks/a_test/directory/spec/default_spec.rb +0 -4
  110. data/test_project/site-cookbooks/a_test/directory/templates/.keep +0 -0
  111. data/test_project/site-cookbooks/a_test/package/attributes/.keep +0 -0
  112. data/test_project/site-cookbooks/a_test/package/files/.keep +0 -0
  113. data/test_project/site-cookbooks/a_test/package/recipes/default.rb +0 -2
  114. data/test_project/site-cookbooks/a_test/package/spec/.keep +0 -0
  115. data/test_project/site-cookbooks/a_test/package/spec/default_spec.rb +0 -4
  116. data/test_project/site-cookbooks/a_test/package/templates/.keep +0 -0
  117. data/test_project/site-cookbooks/a_test/service/attributes/.keep +0 -0
  118. data/test_project/site-cookbooks/a_test/service/files/.keep +0 -0
  119. data/test_project/site-cookbooks/a_test/service/recipes/default.rb +0 -5
  120. data/test_project/site-cookbooks/a_test/service/spec/.keep +0 -0
  121. data/test_project/site-cookbooks/a_test/service/spec/default_spec.rb +0 -6
  122. data/test_project/site-cookbooks/a_test/service/templates/.keep +0 -0
  123. data/test_project/site-cookbooks/b_test/git/attributes/.keep +0 -0
  124. data/test_project/site-cookbooks/b_test/git/files/.keep +0 -0
  125. data/test_project/site-cookbooks/b_test/git/recipes/default.rb +0 -5
  126. data/test_project/site-cookbooks/b_test/git/spec/.keep +0 -0
  127. data/test_project/site-cookbooks/b_test/git/spec/default_spec.rb +0 -5
  128. data/test_project/site-cookbooks/b_test/git/templates/.keep +0 -0
  129. data/test_project/site-cookbooks/b_test/link/attributes/.keep +0 -0
  130. data/test_project/site-cookbooks/b_test/link/files/.keep +0 -0
  131. data/test_project/site-cookbooks/b_test/link/recipes/default.rb +0 -5
  132. data/test_project/site-cookbooks/b_test/link/spec/.keep +0 -0
  133. data/test_project/site-cookbooks/b_test/link/spec/default_spec.rb +0 -5
  134. data/test_project/site-cookbooks/b_test/link/templates/.keep +0 -0
  135. data/test_project/site-cookbooks/b_test/remote_file/attributes/.keep +0 -0
  136. data/test_project/site-cookbooks/b_test/remote_file/files/.keep +0 -0
  137. data/test_project/site-cookbooks/b_test/remote_file/files/remote_file.sh +0 -1
  138. data/test_project/site-cookbooks/b_test/remote_file/recipes/default.rb +0 -9
  139. data/test_project/site-cookbooks/b_test/remote_file/spec/.keep +0 -0
  140. data/test_project/site-cookbooks/b_test/remote_file/spec/default_spec.rb +0 -7
  141. data/test_project/site-cookbooks/b_test/remote_file/templates/.keep +0 -0
  142. data/test_project/site-cookbooks/b_test/template/attributes/.keep +0 -0
  143. data/test_project/site-cookbooks/b_test/template/files/.keep +0 -0
  144. data/test_project/site-cookbooks/b_test/template/recipes/default.rb +0 -5
  145. data/test_project/site-cookbooks/b_test/template/spec/.keep +0 -0
  146. data/test_project/site-cookbooks/b_test/template/spec/default_spec.rb +0 -7
  147. data/test_project/site-cookbooks/b_test/template/templates/.keep +0 -0
  148. data/test_project/site-cookbooks/b_test/template/templates/template.erb +0 -2
  149. data/test_project/site-cookbooks/c_test/execute/attributes/.keep +0 -0
  150. data/test_project/site-cookbooks/c_test/execute/files/.keep +0 -0
  151. data/test_project/site-cookbooks/c_test/execute/recipes/default.rb +0 -6
  152. data/test_project/site-cookbooks/c_test/execute/spec/.keep +0 -0
  153. data/test_project/site-cookbooks/c_test/execute/spec/default_spec.rb +0 -6
  154. data/test_project/site-cookbooks/c_test/execute/templates/.keep +0 -0
  155. data/test_project/site-cookbooks/c_test/remote_directory/attributes/.keep +0 -0
  156. data/test_project/site-cookbooks/c_test/remote_directory/files/.keep +0 -0
  157. data/test_project/site-cookbooks/c_test/remote_directory/recipes/default.rb +0 -10
  158. data/test_project/site-cookbooks/c_test/remote_directory/spec/.keep +0 -0
  159. data/test_project/site-cookbooks/c_test/remote_directory/spec/default_spec.rb +0 -20
  160. data/test_project/site-cookbooks/c_test/remote_directory/templates/.keep +0 -0
  161. data/test_project/site-cookbooks/c_test/remote_directory/templates/remote_dir/a.txt +0 -0
  162. data/test_project/site-cookbooks/c_test/remote_directory/templates/remote_dir/b.txt +0 -0
  163. data/test_project/site-cookbooks/c_test/remote_directory/templates/remote_dir/c.txt +0 -0
  164. data/test_project/site-cookbooks/d_spec/air/attributes/.keep +0 -0
  165. data/test_project/site-cookbooks/d_spec/air/files/.keep +0 -0
  166. data/test_project/site-cookbooks/d_spec/air/recipes/default.rb +0 -0
  167. data/test_project/site-cookbooks/d_spec/air/spec/.keep +0 -0
  168. data/test_project/site-cookbooks/d_spec/air/spec/default_spec.rb +0 -0
  169. data/test_project/site-cookbooks/d_spec/air/templates/.keep +0 -0
  170. data/test_project/spec/spec_helper.rb +0 -33
  171. data/test_project/tmp-nodes/.keep +0 -0
  172. data/test_project/tmp-nodes/test.json +0 -12
@@ -1,123 +0,0 @@
1
- require 'json'
2
- require 'simple_color'
3
- include Rake::DSL if defined? Rake::DSL
4
-
5
- module Itamae
6
- module Mitsurin
7
- class ServerspecTask
8
-
9
- class << self
10
-
11
- task :spec => 'spec:all'
12
- task :default => :spec
13
-
14
- def self.get_roles(node_file)
15
- roles = []
16
- JSON.parse(File.read(node_file))['run_list'].each do |role|
17
- roles << role.gsub(/role\[(.+)\]/, '\1') if /role\[(.+)\]/ === role
18
- end
19
- roles
20
- end
21
-
22
- def self.get_recipes(role)
23
- recipes = []
24
- JSON.parse(File.read("roles/#{role}.json"))['run_list'].each do |recipe|
25
- if /recipe\[(.+)::(.+)\]/ === recipe
26
- recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
27
- else
28
- recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil}
29
- end
30
- end
31
- recipes
32
- end
33
-
34
- def self.get_node_recipes(node_file)
35
- recipes = []
36
- JSON.parse(File.read(node_file))['run_list'].each do |recipe|
37
- if /recipe\[(.+)::(.+)\]/ === recipe
38
- recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
39
- else
40
- recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil} unless /role\[(.+)\]/ === recipe
41
- end
42
- end
43
- recipes
44
- end
45
-
46
- color = SimpleColor.new
47
-
48
- namespace :spec do
49
- all = []
50
- Dir.glob("tmp-nodes/**/*.json").each do |node_file|
51
-
52
- file_name = File.basename(node_file, '.json')
53
- node_attr = JSON.parse(File.read(node_file), symbolize_names: true)
54
-
55
- desc "Spec to #{file_name}"
56
- task node_attr[:environments][:hostname].split(".")[0] do
57
-
58
- begin
59
- recipes = []
60
- get_roles(node_file).each do |role|
61
- recipes << get_recipes(role)
62
- end
63
- get_node_recipes(node_file).each do |recipe|
64
- recipes << recipe
65
- end
66
- rescue Exception => e
67
- puts e.class.to_s + ", " + e.backtrace[0].to_s
68
- puts "nodefile or role error, nodefile:#{node_file} reason:#{e.message}"
69
- exit 1
70
- else
71
- recipes << {'_base' => nil}
72
- recipes.flatten!
73
- end
74
-
75
- node_name = node_attr[:environments][:hostname]
76
- ssh_user = node_attr[:environments][:ssh_user]
77
- ssh_password = node_attr[:environments][:ssh_password]
78
- sudo_password = node_attr[:environments][:sudo_password]
79
- ssh_port = node_attr[:environments][:ssh_port]
80
- ssh_key = node_attr[:environments][:ssh_key]
81
-
82
- node_short = node_name.split(".")[0]
83
- all << node_short
84
-
85
- desc "Run spec to #{file_name}"
86
- ENV['TARGET_HOST'] = node_name
87
- ENV['NODE_FILE'] = node_file
88
- ENV['SSH_PASSWORD'] = ssh_password
89
- ENV['SUDO_PASSWORD'] = sudo_password
90
- ENV['SSH_KEY'] = "keys/#{ssh_key}"
91
- ENV['SSH_PORT'] = ssh_port
92
- ENV['SSH_USER'] = ssh_user
93
-
94
- specs = "bundle exec rspec"
95
-
96
- # recipe load to_spec
97
- spec_pattern = []
98
- recipes.each do |spec_h|
99
- if spec_h["#{spec_h.keys.join}"].nil?
100
- spec_pattern <<
101
- " #{Dir.glob("site-cookbooks/**/#{spec_h.keys.join}/spec/default_spec.rb").join}"
102
- else
103
- spec_pattern <<
104
- " #{Dir.glob("site-cookbooks/**/#{spec_h.keys.join}/spec/#{spec_h["#{spec_h.keys.join}"]}_spec.rb").join}"
105
- end
106
- end
107
- spec_pattern.sort_by! {|item| File.dirname(item)}
108
- specs << spec_pattern.join
109
- run_list_noti = []
110
- spec_pattern.each {|c_spec| run_list_noti << c_spec.split("/") [2]}
111
- color.echos(:red ,%!Run Serverspec to \"#{node_name}\"!)
112
- color.echos(:green, %!Run List to \"#{run_list_noti.uniq.join(", ")}\"!)
113
- st = system specs
114
- exit 1 unless st
115
- end
116
- task :all => all
117
- task :default => :all
118
- end
119
- end
120
- end
121
- end
122
- end
123
- end
@@ -1,84 +0,0 @@
1
- require 'itamae-mitsurin'
2
- require 'itamae-mitsurin/mitsurin'
3
-
4
- module ItamaeMitsurin
5
- module Resource
6
- class AwsEbsVolume < Base
7
- define_attribute :action, default: :create
8
- define_attribute :name, type: String, default_name: true
9
- define_attribute :availability_zone, type: String
10
- define_attribute :device, type: String
11
- define_attribute :instance_id, type: String
12
- define_attribute :volume_type, type: String
13
- define_attribute :size, type: Integer
14
-
15
- def action_create(options)
16
- ec2 = ::Aws::EC2::Client.new
17
- volumes = ec2.describe_volumes(
18
- {
19
- filters: [
20
- {
21
- name: 'tag:Name',
22
- values: [ attributes.name ],
23
- },
24
- ],
25
- }
26
- ).volumes
27
-
28
- if volumes.empty?
29
- @volume = ec2.create_volume(
30
- size: attributes[:size], # attributes.size returns the size of attributes hash
31
- availability_zone: attributes.availability_zone,
32
- volume_type: attributes.volume_type,
33
- )
34
-
35
- ec2.create_tags(
36
- {
37
- resources: [ @volume.volume_id ],
38
- tags: [
39
- {
40
- key: 'Name',
41
- value: attributes.name,
42
- },
43
- ],
44
- }
45
- )
46
-
47
- updated!
48
- sleep(3)
49
- else
50
- @volume = volumes[0]
51
- end
52
-
53
- end
54
-
55
- def action_attach(options)
56
- ec2 = ::Aws::EC2::Client.new
57
- volumes = ec2.describe_volumes(
58
- {
59
- filters: [
60
- {
61
- name: 'tag:Name',
62
- values: [ attributes.name ],
63
- },
64
- ],
65
- }
66
- ).volumes
67
-
68
- unless volumes.empty?
69
- @volume = ec2.attach_volume({
70
- volume_id: @volume.volume_id,
71
- instance_id: attributes.instance_id,
72
- device: attributes.device
73
- })
74
-
75
- updated!
76
- else
77
- @volume = volumes[0]
78
- end
79
-
80
- end
81
- end
82
- end
83
- end
84
-
@@ -1,374 +0,0 @@
1
- require 'itamae-mitsurin'
2
- require 'shellwords'
3
- require 'hashie'
4
-
5
- module ItamaeMitsurin
6
- module Resource
7
- class Base
8
- class EvalContext
9
- attr_reader :attributes
10
- attr_reader :notifications
11
- attr_reader :subscriptions
12
- attr_reader :verify_commands
13
- attr_reader :only_if_command
14
- attr_reader :not_if_command
15
-
16
- def initialize(resource)
17
- @resource = resource
18
-
19
- @attributes = Hashie::Mash.new
20
- @notifications = []
21
- @subscriptions = []
22
- @verify_commands = []
23
- end
24
-
25
- def respond_to_missing?(method, include_private = false)
26
- @resource.class.defined_attributes.has_key?(method) || super
27
- end
28
-
29
- def method_missing(method, *args, &block)
30
- if @resource.class.defined_attributes[method]
31
- if args.size == 1
32
- return @attributes[method] = args.first
33
- elsif args.size == 0 && block_given?
34
- return @attributes[method] = block
35
- elsif args.size == 0
36
- return @attributes[method]
37
- end
38
- end
39
-
40
- super
41
- end
42
-
43
- def notifies(action, resource_desc, timing = :delay)
44
- @notifications << Notification.create(@resource, action, resource_desc, timing)
45
- end
46
-
47
- def subscribes(action, resource_desc, timing = :delay)
48
- @subscriptions << Subscription.create(@resource, action, resource_desc, timing)
49
- end
50
-
51
- def only_if(command)
52
- @only_if_command = command
53
- end
54
-
55
- def not_if(command)
56
- @not_if_command = command
57
- end
58
-
59
- def node
60
- @resource.recipe.runner.node
61
- end
62
-
63
- def run_command(*args)
64
- @resource.recipe.runner.backend.run_command(*args)
65
- end
66
-
67
- # Experimental
68
- def verify(command)
69
- @verify_commands << command
70
- end
71
- end
72
-
73
- @defined_attributes ||= {}
74
-
75
- class << self
76
- attr_reader :defined_attributes
77
- attr_reader :supported_oses
78
-
79
- def inherited(subclass)
80
- subclass.instance_variable_set(
81
- :@defined_attributes,
82
- self.defined_attributes.dup
83
- )
84
- end
85
-
86
- def define_attribute(name, options)
87
- current = @defined_attributes[name.to_sym] || {}
88
- @defined_attributes[name.to_sym] = current.merge(options)
89
- end
90
- end
91
-
92
- define_attribute :action, type: [Symbol, Array], required: true
93
- define_attribute :user, type: String
94
- define_attribute :cwd, type: String
95
-
96
- attr_reader :recipe
97
- attr_reader :resource_name
98
- attr_reader :attributes
99
- attr_reader :current_attributes
100
- attr_reader :subscriptions
101
- attr_reader :notifications
102
- attr_reader :updated
103
-
104
- def initialize(recipe, resource_name, &block)
105
- clear_current_attributes
106
- @recipe = recipe
107
- @resource_name = resource_name
108
- @updated = false
109
-
110
- EvalContext.new(self).tap do |context|
111
- context.instance_eval(&block) if block
112
- @attributes = context.attributes
113
- @notifications = context.notifications
114
- @subscriptions = context.subscriptions
115
- @only_if_command = context.only_if_command
116
- @not_if_command = context.not_if_command
117
- @verify_commands = context.verify_commands
118
- end
119
-
120
- process_attributes
121
- end
122
-
123
- def run(specific_action = nil)
124
- runner.handler.event(:resource, resource_type: resource_type, resource_name: resource_name) do
125
- ItamaeMitsurin.logger.debug "#{resource_type}[#{resource_name}]"
126
-
127
- ItamaeMitsurin.logger.with_indent_if(ItamaeMitsurin.logger.debug?) do
128
- if do_not_run_because_of_only_if?
129
- ItamaeMitsurin.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of only_if attribute"
130
- return
131
- elsif do_not_run_because_of_not_if?
132
- ItamaeMitsurin.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of not_if attribute"
133
- return
134
- end
135
-
136
- [specific_action || attributes.action].flatten.each do |action|
137
- run_action(action)
138
- end
139
-
140
- verify unless runner.dry_run?
141
- if updated?
142
- notify
143
- runner.handler.event(:resource_updated)
144
- end
145
- end
146
-
147
- @updated = false
148
- end
149
- rescue Backend::CommandExecutionError
150
- ItamaeMitsurin.logger.error "#{resource_type}[#{resource_name}] Failed."
151
- exit 2
152
- end
153
-
154
- def action_nothing
155
- # do nothing
156
- end
157
-
158
- def resource_type
159
- self.class.name.split("::").last.scan(/[A-Z][^A-Z]+/).map(&:downcase).join('_')
160
- end
161
-
162
- private
163
-
164
- alias_method :current, :current_attributes
165
-
166
- def run_action(action)
167
- runner.handler.event(:action, action: action) do
168
- original_attributes = @attributes # preserve and restore later
169
- @current_action = action
170
-
171
- clear_current_attributes
172
-
173
- ItamaeMitsurin.logger.debug "#{resource_type}[#{resource_name}] action: #{action}"
174
-
175
- return if action == :nothing
176
-
177
- ItamaeMitsurin.logger.with_indent_if(ItamaeMitsurin.logger.debug?) do
178
- ItamaeMitsurin.logger.debug "(in pre_action)"
179
- pre_action
180
-
181
- ItamaeMitsurin.logger.debug "(in set_current_attributes)"
182
- set_current_attributes
183
-
184
- ItamaeMitsurin.logger.debug "(in show_differences)"
185
- show_differences
186
-
187
- method_name = "action_#{action}"
188
- if runner.dry_run?
189
- unless respond_to?(method_name)
190
- ItamaeMitsurin.logger.error "action #{action.inspect} is unavailable"
191
- end
192
- else
193
- args = [method_name]
194
- if method(method_name).arity == 1
195
- # for plugin compatibility
196
- args << runner.options
197
- end
198
-
199
- public_send(*args)
200
- end
201
-
202
- if different?
203
- updated!
204
- runner.handler.event(:attribute_changed, from: @current_attributes, to: @attributes)
205
- end
206
- end
207
-
208
- @current_action = nil
209
- @attributes = original_attributes
210
- end
211
- end
212
-
213
- def clear_current_attributes
214
- @current_attributes = Hashie::Mash.new
215
- end
216
-
217
- def pre_action
218
- # do nothing
219
- end
220
-
221
- def set_current_attributes
222
- # do nothing
223
- end
224
-
225
- def different?
226
- @current_attributes.each_pair.any? do |key, current_value|
227
- !current_value.nil? &&
228
- !@attributes[key].nil? &&
229
- current_value != @attributes[key]
230
- end
231
- end
232
-
233
- def show_differences
234
- @current_attributes.each_pair do |key, current_value|
235
- value = @attributes[key]
236
- if current_value.nil? && value.nil?
237
- # ignore
238
- elsif current_value.nil? && !value.nil?
239
- ItamaeMitsurin.logger.color :green do
240
- ItamaeMitsurin.logger.info "#{resource_type}[#{resource_name}] #{key} will be '#{value}'"
241
- end
242
- elsif current_value == value || value.nil?
243
- ItamaeMitsurin.logger.debug "#{resource_type}[#{resource_name}] #{key} will not change (current value is '#{current_value}')"
244
- else
245
- ItamaeMitsurin.logger.color :green do
246
- ItamaeMitsurin.logger.info "#{resource_type}[#{resource_name}] #{key} will change from '#{current_value}' to '#{value}'"
247
- end
248
- end
249
- end
250
- end
251
-
252
- def process_attributes
253
- self.class.defined_attributes.each_pair do |key, details|
254
- @attributes[key] ||= @resource_name if details[:default_name]
255
- @attributes[key] = details[:default] if details.has_key?(:default) && !@attributes.has_key?(key)
256
-
257
- if details[:required] && !@attributes[key]
258
- raise Resource::AttributeMissingError, "'#{key}' attribute is required but it is not set."
259
- end
260
-
261
- if @attributes[key] && details[:type]
262
- valid_type = [details[:type]].flatten.any? do |type|
263
- @attributes[key].is_a?(type)
264
- end
265
- unless valid_type
266
- raise Resource::InvalidTypeError, "#{key} attribute should be #{details[:type]}."
267
- end
268
- end
269
- end
270
- end
271
-
272
- def do_not_run_because_of_only_if?
273
- @only_if_command &&
274
- run_command(@only_if_command, error: false).exit_status != 0
275
- end
276
-
277
- def do_not_run_because_of_not_if?
278
- @not_if_command &&
279
- run_command(@not_if_command, error: false).exit_status == 0
280
- end
281
-
282
- def backend
283
- runner.backend
284
- end
285
-
286
- def runner
287
- recipe.runner
288
- end
289
-
290
- def node
291
- runner.node
292
- end
293
-
294
- def run_command(*args)
295
- unless args.last.is_a?(Hash)
296
- args << {}
297
- end
298
-
299
- args.last[:user] ||= attributes.user
300
- args.last[:cwd] ||= attributes.cwd
301
-
302
- backend.run_command(*args)
303
- end
304
-
305
- def check_command(*args)
306
- unless args.last.is_a?(Hash)
307
- args << {}
308
- end
309
-
310
- args.last[:error] = false
311
-
312
- run_command(*args).exit_status == 0
313
- end
314
-
315
- def run_specinfra(type, *args)
316
- command = backend.get_command(type, *args)
317
-
318
- if type.to_s.start_with?("check_")
319
- check_command(command)
320
- else
321
- run_command(command)
322
- end
323
- end
324
-
325
- def shell_escape(str)
326
- str.shellescape
327
- end
328
-
329
- def updated!
330
- ItamaeMitsurin.logger.debug "This resource is updated."
331
- @updated = true
332
- end
333
-
334
- def updated?
335
- @updated
336
- end
337
-
338
- def notify
339
- (notifications + recipe.children.subscribing(self)).each do |notification|
340
- message = "Notifying #{notification.action} to #{notification.action_resource.resource_type} resource '#{notification.action_resource.resource_name}'"
341
-
342
- if notification.delayed?
343
- message << " (delayed)"
344
- elsif notification.immediately?
345
- message << " (immediately)"
346
- end
347
-
348
- ItamaeMitsurin.logger.info message
349
-
350
- if notification.instance_of?(Subscription)
351
- ItamaeMitsurin.logger.info "(because it subscribes this resource)"
352
- end
353
-
354
- if notification.delayed?
355
- @recipe.delayed_notifications << notification
356
- elsif notification.immediately?
357
- notification.run
358
- end
359
- end
360
- end
361
-
362
- def verify
363
- return if @verify_commands.empty?
364
-
365
- ItamaeMitsurin.logger.info "Verifying..."
366
- ItamaeMitsurin.logger.with_indent do
367
- @verify_commands.each do |command|
368
- run_command(command)
369
- end
370
- end
371
- end
372
- end
373
- end
374
- end