right_link 5.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. data/actors/agent_manager.rb +88 -0
  2. data/actors/instance_scheduler.rb +321 -0
  3. data/actors/instance_services.rb +64 -0
  4. data/actors/instance_setup.rb +567 -0
  5. data/bin/cloud +25 -0
  6. data/bin/cook_runner +44 -0
  7. data/bin/deploy +120 -0
  8. data/bin/enroll +385 -0
  9. data/bin/rad +32 -0
  10. data/bin/rchk +29 -0
  11. data/bin/rnac +39 -0
  12. data/bin/rs_connect +33 -0
  13. data/bin/rs_log_level +31 -0
  14. data/bin/rs_ohai +28 -0
  15. data/bin/rs_reenroll +31 -0
  16. data/bin/rs_run_recipe +34 -0
  17. data/bin/rs_run_right_script +34 -0
  18. data/bin/rs_shutdown +33 -0
  19. data/bin/rs_tag +33 -0
  20. data/bin/rs_thunk +33 -0
  21. data/bin/rstat +31 -0
  22. data/bin/system +16 -0
  23. data/ext/Rakefile +18 -0
  24. data/init/config.yml +5 -0
  25. data/init/init.rb +79 -0
  26. data/lib/chef/ohai_setup.rb +51 -0
  27. data/lib/chef/plugins/cloud.rb +91 -0
  28. data/lib/chef/plugins/cloudstack.rb +23 -0
  29. data/lib/chef/plugins/ec2.rb +23 -0
  30. data/lib/chef/plugins/linux/block_device2.rb +24 -0
  31. data/lib/chef/plugins/rackspace.rb +23 -0
  32. data/lib/chef/plugins/rightscale.rb +125 -0
  33. data/lib/chef/plugins/windows/network.rb +114 -0
  34. data/lib/chef/plugins.rb +74 -0
  35. data/lib/chef/providers/dns_dnsmadeeasy_provider.rb +81 -0
  36. data/lib/chef/providers/dns_resource.rb +100 -0
  37. data/lib/chef/providers/executable_schedule_provider.rb +70 -0
  38. data/lib/chef/providers/executable_schedule_resource.rb +144 -0
  39. data/lib/chef/providers/remote_recipe_provider.rb +86 -0
  40. data/lib/chef/providers/remote_recipe_resource.rb +101 -0
  41. data/lib/chef/providers/right_link_tag_provider.rb +73 -0
  42. data/lib/chef/providers/right_link_tag_resource.rb +59 -0
  43. data/lib/chef/providers/right_script_provider.rb +190 -0
  44. data/lib/chef/providers/right_script_resource.rb +113 -0
  45. data/lib/chef/providers/rs_shutdown_provider.rb +75 -0
  46. data/lib/chef/providers/rs_shutdown_resource.rb +55 -0
  47. data/lib/chef/providers/server_collection_provider.rb +66 -0
  48. data/lib/chef/providers/server_collection_resource.rb +93 -0
  49. data/lib/chef/providers/windows/powershell_provider.rb +151 -0
  50. data/lib/chef/providers/windows/powershell_resource.rb +111 -0
  51. data/lib/chef/providers/windows/unsupported_provider.rb +51 -0
  52. data/lib/chef/right_providers.rb +55 -0
  53. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.csproj +104 -0
  54. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ChefNodeCmdlet.dll-Help.xml +141 -0
  55. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Exceptions.cs +182 -0
  56. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeCommand.cs +58 -0
  57. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeRequest.cs +46 -0
  58. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetChefNodeResponse.cs +45 -0
  59. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceCommand.cs +58 -0
  60. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceRequest.cs +46 -0
  61. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetCurrentResourceResponse.cs +45 -0
  62. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceCommand.cs +58 -0
  63. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceRequest.cs +46 -0
  64. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNewResourceResponse.cs +45 -0
  65. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionCommand.cs +178 -0
  66. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionRequest.cs +67 -0
  67. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNextActionResponse.cs +58 -0
  68. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueCommandBase.cs +142 -0
  69. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueRequestBase.cs +64 -0
  70. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/GetNodeValueResponseBase.cs +69 -0
  71. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/JsonTransport.cs +110 -0
  72. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeClient.cs +158 -0
  73. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/PipeServer.cs +142 -0
  74. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
  75. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolConstants.cs +55 -0
  76. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ProtocolUtilities.cs +77 -0
  77. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/ReadMe.txt +53 -0
  78. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeCommand.cs +59 -0
  79. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeRequest.cs +46 -0
  80. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetChefNodeResponse.cs +58 -0
  81. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceCommand.cs +59 -0
  82. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceRequest.cs +46 -0
  83. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetCurrentResourceResponse.cs +40 -0
  84. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceCommand.cs +59 -0
  85. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceRequest.cs +46 -0
  86. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNewResourceResponse.cs +40 -0
  87. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueCommandBase.cs +293 -0
  88. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueRequestBase.cs +75 -0
  89. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/SetNodeValueResponseBase.cs +45 -0
  90. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet/Transport.cs +91 -0
  91. data/lib/chef/windows/ChefNodeCmdlet/ChefNodeCmdlet.sln +35 -0
  92. data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Program.cs +374 -0
  93. data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/Properties/AssemblyInfo.cs +16 -0
  94. data/lib/chef/windows/ChefNodeCmdlet/TestChefNodeCmdlet/TestChefNodeCmdlet.csproj +65 -0
  95. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Program.cs +136 -0
  96. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/Properties/AssemblyInfo.cs +36 -0
  97. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/ReadMe.txt +46 -0
  98. data/lib/chef/windows/ChefNodeCmdlet/TestNextActionCmdlet/TestNextActionCmdlet.csproj +68 -0
  99. data/lib/chef/windows/bin/Newtonsoft.Json.dll +0 -0
  100. data/lib/chef/windows/chef_node_server.rb +463 -0
  101. data/lib/chef/windows/dynamic_powershell_provider.rb +296 -0
  102. data/lib/chef/windows/pipe_server.rb +283 -0
  103. data/lib/chef/windows/powershell_host.rb +285 -0
  104. data/lib/chef/windows/powershell_pipe_server.rb +136 -0
  105. data/lib/chef/windows/powershell_provider_base.rb +92 -0
  106. data/lib/chef/windows/scripts/run_loop.ps1 +105 -0
  107. data/lib/clouds/cloud.rb +557 -0
  108. data/lib/clouds/cloud_factory.rb +250 -0
  109. data/lib/clouds/cloud_utilities.rb +244 -0
  110. data/lib/clouds/clouds/azure.rb +106 -0
  111. data/lib/clouds/clouds/cloudstack.rb +114 -0
  112. data/lib/clouds/clouds/ec2.rb +113 -0
  113. data/lib/clouds/clouds/eucalyptus.rb +46 -0
  114. data/lib/clouds/clouds/google.rb +102 -0
  115. data/lib/clouds/clouds/none.rb +76 -0
  116. data/lib/clouds/clouds/openstack.rb +30 -0
  117. data/lib/clouds/clouds/rackspace-ng.rb +54 -0
  118. data/lib/clouds/clouds/rackspace.rb +78 -0
  119. data/lib/clouds/clouds/softlayer.rb +91 -0
  120. data/lib/clouds/metadata_formatter.rb +108 -0
  121. data/lib/clouds/metadata_provider.rb +128 -0
  122. data/lib/clouds/metadata_source.rb +87 -0
  123. data/lib/clouds/metadata_sources/certificate_metadata_source.rb +207 -0
  124. data/lib/clouds/metadata_sources/config_drive_metadata_source.rb +129 -0
  125. data/lib/clouds/metadata_sources/file_metadata_source.rb +74 -0
  126. data/lib/clouds/metadata_sources/http_metadata_source.rb +277 -0
  127. data/lib/clouds/metadata_sources/selective_metadata_source.rb +122 -0
  128. data/lib/clouds/metadata_tree_climber.rb +144 -0
  129. data/lib/clouds/metadata_writer.rb +155 -0
  130. data/lib/clouds/metadata_writers/dictionary_metadata_writer.rb +72 -0
  131. data/lib/clouds/metadata_writers/ruby_metadata_writer.rb +76 -0
  132. data/lib/clouds/metadata_writers/shell_metadata_writer.rb +121 -0
  133. data/lib/clouds/register_clouds.rb +34 -0
  134. data/lib/clouds.rb +32 -0
  135. data/lib/gem_dependencies.rb +83 -0
  136. data/lib/git_hooks/commit-msg.rb +7 -0
  137. data/lib/instance/agent_config.rb +168 -0
  138. data/lib/instance/agent_watcher.rb +233 -0
  139. data/lib/instance/audit_cook_stub.rb +104 -0
  140. data/lib/instance/audit_proxy.rb +247 -0
  141. data/lib/instance/bundle_queue.rb +104 -0
  142. data/lib/instance/cook/agent_connection.rb +109 -0
  143. data/lib/instance/cook/audit_logger.rb +165 -0
  144. data/lib/instance/cook/audit_stub.rb +142 -0
  145. data/lib/instance/cook/ca-bundle.crt +2794 -0
  146. data/lib/instance/cook/chef_state.rb +211 -0
  147. data/lib/instance/cook/cook.rb +306 -0
  148. data/lib/instance/cook/cook_state.rb +298 -0
  149. data/lib/instance/cook/cookbook_path_mapping.rb +66 -0
  150. data/lib/instance/cook/cookbook_repo_retriever.rb +190 -0
  151. data/lib/instance/cook/executable_sequence.rb +765 -0
  152. data/lib/instance/cook/external_parameter_gatherer.rb +190 -0
  153. data/lib/instance/cook/repose_downloader.rb +349 -0
  154. data/lib/instance/cook/shutdown_request_proxy.rb +121 -0
  155. data/lib/instance/cook.rb +41 -0
  156. data/lib/instance/downloader.rb +208 -0
  157. data/lib/instance/duplicable.rb +67 -0
  158. data/lib/instance/exceptions.rb +49 -0
  159. data/lib/instance/executable_sequence_proxy.rb +278 -0
  160. data/lib/instance/instance_commands.rb +577 -0
  161. data/lib/instance/instance_state.rb +633 -0
  162. data/lib/instance/json_utilities.rb +102 -0
  163. data/lib/instance/login_manager.rb +533 -0
  164. data/lib/instance/login_user_manager.rb +522 -0
  165. data/lib/instance/message_encoder.rb +118 -0
  166. data/lib/instance/multi_thread_bundle_queue.rb +232 -0
  167. data/lib/instance/operation_context.rb +60 -0
  168. data/lib/instance/options_bag.rb +65 -0
  169. data/lib/instance/payload_formatter.rb +46 -0
  170. data/lib/instance/policy.rb +53 -0
  171. data/lib/instance/policy_audit.rb +100 -0
  172. data/lib/instance/policy_manager.rb +146 -0
  173. data/lib/instance/reenroll_manager.rb +104 -0
  174. data/lib/instance/right_scripts_cookbook.rb +181 -0
  175. data/lib/instance/shutdown_request.rb +221 -0
  176. data/lib/instance/single_thread_bundle_queue.rb +189 -0
  177. data/lib/instance/volume_management.rb +450 -0
  178. data/lib/instance.rb +50 -0
  179. data/lib/repo_conf_generators/apt_conf_generators.rb +106 -0
  180. data/lib/repo_conf_generators/gem_conf_generators.rb +80 -0
  181. data/lib/repo_conf_generators/rightscale_conf_generators.rb +254 -0
  182. data/lib/repo_conf_generators/rightscale_key.pub +17 -0
  183. data/lib/repo_conf_generators/yum_conf_generators.rb +225 -0
  184. data/lib/repo_conf_generators.rb +30 -0
  185. data/lib/run_shell.rb +28 -0
  186. data/scripts/agent_checker.rb +571 -0
  187. data/scripts/agent_controller.rb +247 -0
  188. data/scripts/agent_deployer.rb +148 -0
  189. data/scripts/bundle_runner.rb +336 -0
  190. data/scripts/cloud_controller.rb +176 -0
  191. data/scripts/log_level_manager.rb +142 -0
  192. data/scripts/ohai_runner.rb +33 -0
  193. data/scripts/reenroller.rb +193 -0
  194. data/scripts/server_importer.rb +293 -0
  195. data/scripts/shutdown_client.rb +183 -0
  196. data/scripts/system_configurator.rb +367 -0
  197. data/scripts/tagger.rb +381 -0
  198. data/scripts/thunker.rb +356 -0
  199. metadata +418 -0
@@ -0,0 +1,211 @@
1
+ #
2
+ # Copyright (c) 2009-2012 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'fileutils'
24
+
25
+ module RightScale
26
+
27
+ # Manages and persists chef state (run list and attributes)
28
+ class ChefState
29
+
30
+ # Path to JSON file where current chef state is serialized
31
+ STATE_FILE = File.join(InstanceState::STATE_DIR, 'chef.js')
32
+
33
+ # Path to JSON file where past scripts are serialized
34
+ SCRIPTS_FILE = File.join(InstanceState::STATE_DIR, 'past_scripts.js')
35
+
36
+ class ChefStateNotInitialized < Exception; end
37
+
38
+ class << self
39
+ # Load chef state from file
40
+ #
41
+ # @param [String] agent_id identity
42
+ # @param [String] secret for encryption or nil
43
+ # @param [TrueClass|FalseClass] reset persisted state if true, load it otherwise
44
+ def init(agent_id, secret, reset)
45
+ return true if initialized? && !reset
46
+ @@encoder = MessageEncoder.for_agent(agent_id, secret)
47
+ @@attributes = {}
48
+ @@past_scripts = []
49
+ if reset
50
+ save_state
51
+ else
52
+ load_state
53
+ end
54
+ true
55
+ end
56
+
57
+ # Was 'init' ever called?
58
+ # Note: Accessing or setting the chef state calls 'init'
59
+ #
60
+ # === Return
61
+ # true:: If 'init' has been called
62
+ # false:: Otherwise
63
+ def initialized?
64
+ !!defined?(@@attributes)
65
+ end
66
+
67
+ # Current node attributes
68
+ #
69
+ # === Return
70
+ # attributes(Hash):: Current node attributes
71
+ def attributes
72
+ ensure_initialized
73
+ @@attributes
74
+ end
75
+
76
+ # Current list of scripts that have already executed
77
+ #
78
+ # === Return
79
+ # (Array[(String)]) Scripts that have already executed
80
+ def past_scripts
81
+ ensure_initialized
82
+ @@past_scripts
83
+ end
84
+
85
+ # Set node attributes
86
+ # Note: can't set it to nil. Setting the attributes to nil will
87
+ # cause the attributes to be initialized if they haven't yet but won't
88
+ # assign the value nil to them.
89
+ #
90
+ # === Parameters
91
+ # attributes(Hash):: Node attributes
92
+ #
93
+ # === Return
94
+ # true:: Always return true
95
+ def attributes=(val)
96
+ ensure_initialized
97
+ @@attributes = val if val
98
+ save_state
99
+ end
100
+
101
+ # Merge given attributes into node attributes
102
+ #
103
+ # === Parameters
104
+ # attribs(Hash):: Attributes to be merged
105
+ #
106
+ # === Return
107
+ # true:: Always return true
108
+ def merge_attributes(attribs)
109
+ self.attributes = ::RightSupport::Data::HashTools.deep_merge!(attributes, attribs) if attribs
110
+ true
111
+ end
112
+
113
+ # Record script execution in scripts file
114
+ #
115
+ # === Parameters
116
+ # nickname(String):: Nickname of RightScript which successfully executed
117
+ #
118
+ # === Return
119
+ # true:: If script was added to past scripts collection
120
+ # false:: If script was already in past scripts collection
121
+ def record_script_execution(nickname)
122
+ ensure_initialized
123
+ new_script = !@@past_scripts.include?(nickname)
124
+ @@past_scripts << nickname if new_script
125
+ # note that we only persist state on successful execution of bundle.
126
+ new_script
127
+ end
128
+
129
+ # Save node attributes to file
130
+ # Note: Attributes are saved only when runlist ran on default thread
131
+ #
132
+ # === Return
133
+ # true:: Always return true
134
+ def save_state
135
+ if Cook.instance.has_default_thread?
136
+ begin
137
+ FileUtils.touch(STATE_FILE)
138
+ File.chmod(0600, STATE_FILE)
139
+ write_encoded_data(STATE_FILE, { 'attributes' => @@attributes })
140
+ RightScale::JsonUtilities::write_json(SCRIPTS_FILE, @@past_scripts)
141
+ rescue Exception => e
142
+ Log.warning("Failed to save node attributes: #{e.message}")
143
+ end
144
+ end
145
+ true
146
+ end
147
+
148
+ private
149
+ def ensure_initialized
150
+ raise ChefStateNotInitialized if !initialized?
151
+ end
152
+
153
+ # Loads Chef state from file(s), if any.
154
+ #
155
+ # === Return
156
+ # always true
157
+ def load_state
158
+ # load the previously saved Chef node attributes, if any.
159
+ if File.file?(STATE_FILE)
160
+ begin
161
+ js = read_encoded_data(STATE_FILE)
162
+ @@attributes = js['attributes'] || {}
163
+ Log.debug("Successfully loaded chef state")
164
+ rescue Exception => e
165
+ Log.error("Failed to load chef state", e)
166
+ end
167
+ else
168
+ @@attributes = {}
169
+ Log.debug("No previous state to load")
170
+ end
171
+
172
+ # load the list of previously run scripts
173
+ @@past_scripts = RightScale::JsonUtilities::read_json(SCRIPTS_FILE) rescue [] if File.file?(SCRIPTS_FILE)
174
+ Log.debug("Past scripts: #{@@past_scripts.inspect}")
175
+ true
176
+ end
177
+
178
+ # Encode and save an object to a file
179
+ #
180
+ # === Parameters
181
+ # path(String):: Path to file being written
182
+ # data(Object):: Object to be saved
183
+ #
184
+ # === Return
185
+ # true:: Always return true
186
+ def write_encoded_data(path, data)
187
+ dir = File.dirname(path)
188
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
189
+ File.open(path, 'w') do |f|
190
+ f.flock(File::LOCK_EX)
191
+ f.write(@@encoder.encode(data))
192
+ end
193
+ true
194
+ end
195
+
196
+ # Read encoded content form given file and return the origin al object
197
+ #
198
+ # === Parameters
199
+ # path(String):: Path to file being written
200
+ #
201
+ # === Return
202
+ # data(Object):: Object restored from file content
203
+ def read_encoded_data(path)
204
+ File.open(path, "r") do |f|
205
+ f.flock(File::LOCK_EX)
206
+ return @@encoder.decode(f.read)
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,306 @@
1
+ #
2
+ # Copyright (c) 2010-2012 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'right_agent'
24
+ require 'right_agent/core_payload_types'
25
+
26
+
27
+ require File.normalize_path(File.join(File.dirname(__FILE__), '..', '..', 'chef', 'right_providers'))
28
+ require File.normalize_path(File.join(File.dirname(__FILE__), '..', '..', 'chef', 'plugins'))
29
+
30
+ module RightScale
31
+
32
+ class Cook
33
+
34
+ # Name of agent running the cook process
35
+ AGENT_NAME = 'instance'
36
+
37
+ # Exceptions
38
+ class TagError < Exception; end
39
+ class BlockingError < Exception; end
40
+
41
+ # Run bundle given in stdin
42
+ def run
43
+ # 1. Load configuration settings
44
+ options = OptionsBag.load
45
+ agent_id = options[:identity]
46
+ AgentConfig.root_dir = options[:root_dir]
47
+
48
+ Log.program_name = 'RightLink'
49
+ Log.facility = 'user'
50
+ Log.log_to_file_only(options[:log_to_file_only])
51
+ Log.init(agent_id, options[:log_path])
52
+ Log.level = CookState.log_level
53
+ # add an additional logger if the agent is set to log to an alternate
54
+ # location (install, operate, decommission, ...)
55
+ Log.add_logger(::Logger.new(CookState.log_file)) if CookState.log_file
56
+
57
+ Log.info("[cook] Process starting up with dev tags: [#{CookState.startup_tags.select { |tag| tag.include?(CookState::DEV_TAG_NAMESPACE)}.join(', ')}]")
58
+ fail('Missing command server listen port') unless options[:listen_port]
59
+ fail('Missing command cookie') unless options[:cookie]
60
+ @client = CommandClient.new(options[:listen_port], options[:cookie])
61
+ ShutdownRequestProxy.init(@client)
62
+
63
+ # 2. Retrieve bundle
64
+ input = gets.chomp
65
+ begin
66
+ bundle = RightScale::MessageEncoder.for_agent(agent_id).decode(input)
67
+ rescue Exception => e
68
+ fail('Invalid bundle', e.message)
69
+ end
70
+
71
+ fail('Missing bundle', 'No bundle to run') if bundle.nil?
72
+
73
+ @thread_name = bundle.runlist_policy.thread_name if bundle.respond_to?(:runlist_policy) && bundle.runlist_policy
74
+ @thread_name ||= RightScale::AgentConfig.default_thread_name
75
+ options[:thread_name] = @thread_name
76
+
77
+ # Chef state needs the server secret so it can encrypt state on disk.
78
+ # The secret is the same for all instances of the server (i.e. is still
79
+ # valid after stop and restart server).
80
+ server_secret = bundle.server_secret || AgentConfig.default_server_secret
81
+ ChefState.init(agent_id, server_secret, reset=false)
82
+
83
+ # 3. Run bundle
84
+ @@instance = self
85
+ success = nil
86
+ Log.debug("[cook] Thread name associated with bundle = #{@thread_name}")
87
+ gatherer = ExternalParameterGatherer.new(bundle, options)
88
+ sequence = ExecutableSequence.new(bundle)
89
+ EM.threadpool_size = 1
90
+ EM.error_handler do |e|
91
+ Log.error("Execution failed", e, :trace)
92
+ fail('Exception caught', "The following exception was caught during execution:\n #{e.message}")
93
+ end
94
+ EM.run do
95
+ begin
96
+ AuditStub.instance.init(options)
97
+ gatherer.callback { EM.defer { sequence.run } }
98
+ gatherer.errback { success = false; report_failure(gatherer) }
99
+ sequence.callback { success = true; send_inputs_patch(sequence) }
100
+ sequence.errback { success = false; report_failure(sequence) }
101
+
102
+ EM.defer { gatherer.run }
103
+ rescue Exception => e
104
+ fail('Execution failed', Log.format("Execution failed", e, :trace))
105
+ end
106
+ end
107
+
108
+ rescue Exception => e
109
+ fail('Execution failed', Log.format("Run failed", e, :trace))
110
+
111
+ ensure
112
+ Log.info("[cook] Process stopping")
113
+ exit(1) unless success
114
+ end
115
+
116
+ # Determines if the current cook process has the default thread for purposes
117
+ # of concurrency with non-defaulted cooks.
118
+ def has_default_thread?
119
+ ::RightScale::AgentConfig.default_thread_name == @thread_name
120
+ end
121
+
122
+ # Helper method to send a request to one or more targets with no response expected
123
+ # See InstanceCommands for details
124
+ def send_push(type, payload = nil, target = nil, opts = {})
125
+ cmd = {:name => :send_push, :type => type, :payload => payload, :target => target, :options => opts}
126
+ # Need to execute on EM main thread where command client is running
127
+ EM.next_tick { @client.send_command(cmd) }
128
+ end
129
+
130
+ # Add given tag to tags exposed by corresponding server
131
+ #
132
+ # === Parameters
133
+ # tag(String):: Tag to be added
134
+ #
135
+ # === Return
136
+ # result(Hash):: contents of response
137
+ def query_tags(tags, agent_ids=nil, timeout=120)
138
+ cmd = { :name => :query_tags, :tags => tags }
139
+ cmd[:agent_ids] = agent_ids unless agent_ids.nil? || agent_ids.empty?
140
+ response = blocking_request(cmd, timeout)
141
+ begin
142
+ result = OperationResult.from_results(load(response, "Unexpected response #{response.inspect}"))
143
+ raise TagError.new("Query tags failed: #{result.content}") unless result.success?
144
+ return result.content
145
+ rescue
146
+ raise TagError.new("Query tags failed: #{response.inspect}")
147
+ end
148
+ end
149
+
150
+ # Add given tag to tags exposed by corresponding server
151
+ #
152
+ # === Parameters
153
+ # tag(String):: Tag to be added
154
+ # timeout(Fixnum):: Number of seconds to wait for agent response
155
+ #
156
+ # === Return
157
+ # true:: Always return true
158
+ def add_tag(tag_name, timeout)
159
+ cmd = { :name => :add_tag, :tag => tag_name }
160
+ response = blocking_request(cmd, timeout)
161
+ result = OperationResult.from_results(load(response, "Unexpected response #{response.inspect}"))
162
+ if result.success?
163
+ ::Chef::Log.info("Successfully added tag #{tag_name}")
164
+ else
165
+ raise TagError.new("Add tag failed: #{result.content}")
166
+ end
167
+ true
168
+ end
169
+
170
+ # Remove given tag from tags exposed by corresponding server
171
+ #
172
+ # === Parameters
173
+ # tag(String):: Tag to be removed
174
+ # timeout(Fixnum):: Number of seconds to wait for agent response
175
+ #
176
+ # === Return
177
+ # true:: Always return true
178
+ def remove_tag(tag_name, timeout)
179
+ cmd = { :name => :remove_tag, :tag => tag_name }
180
+ response = blocking_request(cmd, timeout)
181
+ result = OperationResult.from_results(load(response, "Unexpected response #{response.inspect}"))
182
+ if result.success?
183
+ ::Chef::Log.info("Successfully removed tag #{tag_name}")
184
+ else
185
+ raise TagError.new("Remove tag failed: #{result.content}")
186
+ end
187
+ true
188
+ end
189
+
190
+ # Retrieve current instance tags
191
+ #
192
+ # === Parameters
193
+ # timeout(Fixnum):: Number of seconds to wait for agent response
194
+ def load_tags(timeout)
195
+ cmd = { :name => :get_tags }
196
+ res = blocking_request(cmd, timeout)
197
+ raise TagError.new("Retrieving current tags failed: #{res.inspect}") unless res.kind_of?(Array)
198
+
199
+ ::Chef::Log.info("Successfully loaded current tags: '#{res.join("', '")}'")
200
+ res
201
+ end
202
+
203
+ # Access cook instance from anywhere to send requests to core through
204
+ # command protocol
205
+ def self.instance
206
+ @@instance
207
+ end
208
+
209
+ protected
210
+
211
+ # Initialize instance variables
212
+ def initialize
213
+ @client = nil
214
+ end
215
+
216
+ # Report inputs patch to core
217
+ def send_inputs_patch(sequence)
218
+ if has_default_thread?
219
+ begin
220
+ cmd = { :name => :set_inputs_patch, :patch => sequence.inputs_patch }
221
+ @client.send_command(cmd)
222
+ rescue Exception => e
223
+ fail('Failed to update inputs', Log.format("Failed to apply inputs patch after execution", e, :trace))
224
+ end
225
+ end
226
+ true
227
+ ensure
228
+ stop
229
+ end
230
+
231
+ # Report failure to core
232
+ def report_failure(subject)
233
+ begin
234
+ AuditStub.instance.append_error(subject.failure_title, :category => RightScale::EventCategories::CATEGORY_ERROR) if subject.failure_title
235
+ AuditStub.instance.append_error(subject.failure_message) if subject.failure_message
236
+ rescue Exception => e
237
+ fail('Failed to report failure', Log.format("Failed to report failure after execution", e, :trace))
238
+ ensure
239
+ stop
240
+ end
241
+ end
242
+
243
+ # Print failure message and exit abnormally
244
+ def fail(title, message=nil)
245
+ $stderr.puts title
246
+ $stderr.puts message || title
247
+ if @client
248
+ @client.stop { AuditStub.instance.stop { exit(1) } }
249
+ else
250
+ exit(1)
251
+ end
252
+ end
253
+
254
+ # Stop command client then stop auditor stub then EM
255
+ def stop
256
+ AuditStub.instance.stop do
257
+ @client.stop do |timeout|
258
+ Log.info('[cook] Failed to stop command client cleanly, forcing shutdown...') if timeout
259
+ EM.stop
260
+ end
261
+ end
262
+ end
263
+
264
+ # Provides a blocking request for the given command
265
+ # Can only be called when on EM defer thread
266
+ #
267
+ # === Parameters
268
+ # cmd(Hash):: request to send
269
+ #
270
+ # === Return
271
+ # response(String):: raw response
272
+ #
273
+ # === Raise
274
+ # BlockingError:: If request called when on EM main thread
275
+ def blocking_request(cmd, timeout)
276
+ raise BlockingError, "Blocking request not allowed on EM main thread for command #{cmd.inspect}" if EM.reactor_thread?
277
+ # Use a queue to block and wait for response
278
+ response_queue = Queue.new
279
+ # Need to execute on EM main thread where command client is running
280
+ EM.next_tick { @client.send_command(cmd, false, timeout) { |response| response_queue << response } }
281
+ return response_queue.shift
282
+ end
283
+
284
+ # Load serialized content
285
+ # fail if serialized data is invalid
286
+ #
287
+ # === Parameters
288
+ # data(String):: Serialized content
289
+ # error_message(String):: Error to be logged/audited in case of failure
290
+ # format(Symbol):: Serialization format
291
+ #
292
+ # === Return
293
+ # content(String):: Unserialized content
294
+ def load(data, error_message, format = nil)
295
+ serializer = Serializer.new(format)
296
+ content = nil
297
+ begin
298
+ content = serializer.load(data)
299
+ rescue Exception => e
300
+ fail(error_message, "Failed to load #{serializer.format.to_s} data (#{e}):\n#{data.inspect}")
301
+ end
302
+ content
303
+ end
304
+
305
+ end
306
+ end