right_link 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,567 @@
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 File.normalize_path(File.join(File.dirname(__FILE__), '..', 'lib', 'instance', 'volume_management'))
24
+
25
+ class InstanceSetup
26
+
27
+ include RightScale::Actor
28
+ include RightScale::OperationResultHelper
29
+ include RightScale::VolumeManagementHelper
30
+
31
+ CONFIG_YAML_FILE = File.normalize_path(File.join(RightScale::Platform.filesystem.right_link_static_state_dir, 'features.yml'))
32
+
33
+ CONFIG=\
34
+ if File.exists?(CONFIG_YAML_FILE)
35
+ RightSupport::Config.features(CONFIG_YAML_FILE)
36
+ else
37
+ RightSupport::Config.features({})
38
+ end
39
+
40
+ expose :report_state
41
+
42
+ # Amount of seconds to wait between set_r_s_version calls attempts
43
+ RECONNECT_DELAY = 5
44
+
45
+ # Amount of seconds to wait before shutting down if boot hasn't completed
46
+ SUICIDE_DELAY = 45 * 60
47
+
48
+ # Time between attempts to get missing inputs.
49
+ MISSING_INPUT_RETRY_DELAY_SECS = 20
50
+
51
+ # Maximum time between nag audits for missing inputs.
52
+ MISSING_INPUT_AUDIT_DELAY_SECS = 2 * 60
53
+
54
+ # Tag set on instances that are part of an array
55
+ AUTO_LAUNCH_TAG ='rs_launch:type=auto'
56
+
57
+ # How long to wait for tag query before proceeding to boot sequence
58
+ INITIAL_TAG_QUERY_TIMEOUT = 20
59
+
60
+ # Boot if and only if instance state is 'booting'
61
+ # Prime timer for shutdown on unsuccessful boot ('suicide' functionality)
62
+ #
63
+ # === Parameters
64
+ # agent(RightScale::Agent):: Host agent
65
+ def initialize(agent)
66
+ @agent_identity = agent.identity
67
+ @got_boot_bundle = false
68
+ EM.threadpool_size = 1
69
+ RightScale::InstanceState.init(@agent_identity)
70
+
71
+ # Reset log level here even though already initialized in the agent
72
+ # so that InstanceState gets notified of the level in use
73
+ RightScale::Log.level = agent.options[:log_level] if agent.options[:log_level]
74
+
75
+ # Schedule boot sequence, don't run it now so agent is registered first
76
+ if RightScale::InstanceState.value == 'booting'
77
+ EM.next_tick { init_boot }
78
+ else
79
+ RightScale::Sender.instance.initialize_offline_queue
80
+ RightScale::Sender.instance.start_offline_queue
81
+
82
+ # handle case of a decommission which was abruptly interrupted and never
83
+ # shutdown the instance (likely due to a decommission script which induced
84
+ # an unexpected fault in the agent).
85
+ #
86
+ # note that upon successfuly reboot (or start of a stopped instance) the
87
+ # instance state file is externally reset to a rebooting state (thus
88
+ # avoiding the dreaded infinite reboot/stop scenario).
89
+ if RightScale::InstanceState.value == 'decommissioning' && (kind = RightScale::InstanceState.decommission_type)
90
+ EM.next_tick { recover_decommission(user_id = nil, skip_db_update = false, kind) }
91
+ end
92
+ end
93
+ end
94
+
95
+ # Retrieve current instance state
96
+ #
97
+ # === Return
98
+ # (RightScale::OperationResult):: Success operation result containing instance state
99
+ def report_state
100
+ success_result(RightScale::InstanceState.value)
101
+ end
102
+
103
+ # Handle disconnected notification from broker, enter offline mode
104
+ #
105
+ # === Parameters
106
+ # status(Symbol):: Connection status, one of :connected or :disconnected
107
+ #
108
+ # === Return
109
+ # true:: Always return true
110
+ def connection_status(status)
111
+ if status == :disconnected
112
+ RightScale::Sender.instance.enable_offline_mode
113
+ else
114
+ RightScale::Sender.instance.disable_offline_mode
115
+ end
116
+ true
117
+ end
118
+
119
+ protected
120
+
121
+ # We start off by setting the instance 'r_s_version' in the core site,
122
+ # then perform an initial tag query before proceeding with the boot
123
+ # sequence.
124
+ #
125
+ # === Return
126
+ # true:: Always return true
127
+ def init_boot
128
+ RightScale::Sender.instance.initialize_offline_queue
129
+ payload = {:agent_identity => @agent_identity,
130
+ :r_s_version => RightScale::AgentConfig.protocol_version,
131
+ :resource_uid => RightScale::InstanceState.resource_uid}
132
+ req = RightScale::IdempotentRequest.new('/booter/declare', payload, :retry_on_error => true)
133
+ req.callback do |res|
134
+ RightScale::Sender.instance.start_offline_queue
135
+ init_fetch_tags
136
+ end
137
+ req.run
138
+ true
139
+ end
140
+
141
+ # Perform a one=time initial tag query in order to ensure that InstanceState
142
+ # and CookState have the fresh possible list of tags. This is advantageous
143
+ # because the agent's tags can affect the agent and the cook subprocess
144
+ # in many ways.
145
+ #
146
+ # === Return
147
+ # true:: Always return true
148
+ def init_fetch_tags
149
+ RightScale::Log.info "Performing initial-startup tag query"
150
+ RightScale::AgentTagManager.instance.tags(:timeout=>INITIAL_TAG_QUERY_TIMEOUT) do |tags|
151
+ if tags.is_a?(String)
152
+ # AgentTagManager could give us a String (error message)
153
+ RightScale::Log.error("Failed to query tags during initial startup: #{tags}")
154
+ else
155
+ #CookState is also updated in ExecutableSequenceProxy#run, but doing
156
+ #it here ensures that CookState is initially convergent with InstanceState.
157
+ RightScale::InstanceState.startup_tags = tags
158
+ RightScale::CookState.update(RightScale::InstanceState)
159
+
160
+ # we are no longer freezing log level for v5.8+
161
+ tagged_log_level = ::RightScale::CookState.dev_log_level
162
+ RightScale::Log.level = tagged_log_level if tagged_log_level
163
+ RightScale::Log.info("Tags discovered at initial startup: #{tags.inspect} (dev mode = #{::RightScale::CookState.dev_mode_enabled?})")
164
+ end
165
+
166
+ # Setup suicide timer which will cause instance to shutdown if the rs_launch:type=auto tag
167
+ # is set and the instance has not gotten its boot bundle after SUICIDE_DELAY seconds and this is
168
+ # the first time this instance boots
169
+ if RightScale::InstanceState.initial_boot?
170
+ @suicide_timer = EM::Timer.new(SUICIDE_DELAY) do
171
+ if RightScale::InstanceState.startup_tags.include?(AUTO_LAUNCH_TAG) && !@got_boot_bundle
172
+ msg = "Shutting down after having tried to boot for #{SUICIDE_DELAY / 60} minutes"
173
+ RightScale::Log.error(msg)
174
+ @audit.append_error(msg, :category => RightScale::EventCategories::CATEGORY_ERROR) if @audit
175
+ RightScale::Platform.controller.shutdown
176
+ end
177
+ end
178
+ end
179
+
180
+ enable_managed_login
181
+ end
182
+
183
+ true
184
+ end
185
+
186
+ # Enable managed SSH for this instance, then continue with boot. Ensures that
187
+ # managed SSH users can login to troubleshoot stranded and other 'interesting' events
188
+ #
189
+ # === Return
190
+ # true:: Always return true
191
+ def enable_managed_login
192
+ if !RightScale::LoginManager.instance.supported_by_platform?
193
+ setup_volumes
194
+ else
195
+ ssh_host_keys = RightScale::LoginManager.instance.get_ssh_host_keys
196
+ req = RightScale::IdempotentRequest.new('/booter/get_login_policy',
197
+ { :agent_identity => @agent_identity,
198
+ :ssh_host_keys=>ssh_host_keys })
199
+
200
+ req.callback do |policy|
201
+ audit = RightScale::AuditProxy.new(policy.audit_id)
202
+ begin
203
+ RightScale::LoginManager.instance.update_policy(policy, @agent_identity) do |audit_content|
204
+ if audit_content
205
+ audit.create_new_section('Managed login enabled')
206
+ audit.append_info(audit_content)
207
+ end
208
+ end
209
+ rescue Exception => e
210
+ audit.create_new_section('Failed to enable managed login')
211
+ audit.append_error("Error applying login policy: #{e}", :category => RightScale::EventCategories::CATEGORY_ERROR)
212
+ RightScale::Log.error('Failed to enable managed login', e, :trace)
213
+ end
214
+
215
+ setup_volumes
216
+ end
217
+
218
+ req.errback do |res|
219
+ RightScale::Log.error('Could not get login policy', res)
220
+ boot
221
+ end
222
+
223
+ req.run
224
+ end
225
+ end
226
+
227
+ # Attach EBS volumes to drive letters on Windows
228
+ #
229
+ # === Return
230
+ # true:: Always return true
231
+ def setup_volumes
232
+ # managing planned volumes is currently only needed in Windows and only if
233
+ # this is not a reboot scenario.
234
+ if !RightScale::Platform.windows? || RightScale::InstanceState.reboot?
235
+ boot
236
+ else
237
+ RightScale::AuditProxy.create(@agent_identity, 'Planned volume management') do |audit|
238
+ @audit = audit
239
+ manage_planned_volumes do
240
+ @audit = nil
241
+ boot
242
+ end
243
+ end
244
+ end
245
+ true
246
+ end
247
+
248
+ # Retrieve software repositories and configure mirrors accordingly then proceed to
249
+ # retrieving and running boot bundle.
250
+ #
251
+ # === Return
252
+ # true:: Always return true
253
+ def boot
254
+ req = RightScale::IdempotentRequest.new('/booter/get_repositories', { :agent_identity => @agent_identity })
255
+
256
+ req.callback do |res|
257
+ @audit = RightScale::AuditProxy.new(res.audit_id)
258
+ if CONFIG['package_repositories']['freeze'] && !RightScale::Platform.windows? && !RightScale::Platform.darwin?
259
+ reps = res.repositories
260
+ audit_content = "Using the following software repositories:\n"
261
+ reps.each { |rep| audit_content += " - #{rep.to_s}\n" }
262
+ @audit.create_new_section('Configuring software repositories')
263
+ @audit.append_info(audit_content)
264
+ configure_repositories(reps)
265
+ @audit.update_status('Software repositories configured')
266
+ end
267
+ @audit.create_new_section('Preparing boot bundle')
268
+ prepare_boot_bundle do |prep_res|
269
+ if prep_res.success?
270
+ @audit.update_status('Boot bundle ready')
271
+ run_boot_bundle(prep_res.content) do |boot_res|
272
+ if boot_res.success?
273
+ # want to go operational only if no immediate shutdown request.
274
+ # immediate shutdown requires we stay in the current (booting)
275
+ # state pending full reboot/restart of instance so that we don't
276
+ # bounce between operational and booting in a multi-reboot case.
277
+ # if shutdown is deferred, then go operational before shutdown.
278
+ shutdown_request = RightScale::ShutdownRequest.instance
279
+ if shutdown_request.immediately?
280
+ # process the shutdown request immediately since the
281
+ # operational bundles queue will not start in this case.
282
+ errback = lambda { strand("Failed to #{shutdown_request} while running boot sequence") }
283
+ shutdown_request.process(errback, @audit)
284
+ else
285
+ # any deferred shutdown request was submitted to the
286
+ # operational bundles queue and will execute later.
287
+ RightScale::InstanceState.value = 'operational'
288
+ end
289
+ else
290
+ strand('Failed to run boot sequence', boot_res)
291
+ end
292
+ end
293
+ else
294
+ strand('Failed to prepare boot bundle', prep_res)
295
+ end
296
+ end
297
+ end
298
+
299
+ req.errback do|res|
300
+ strand('Failed to retrieve software repositories', res)
301
+ end
302
+
303
+ req.run
304
+ true
305
+ end
306
+
307
+ # Log error to local log file and set instance state to stranded
308
+ #
309
+ # === Parameters
310
+ # msg(String):: Error message that will be audited and logged
311
+ # res(RightScale::OperationResult):: Operation result with additional information
312
+ #
313
+ # === Return
314
+ # true:: Always return true
315
+ def strand(msg, res = nil)
316
+ # attempt to provide details of exception or result which caused stranding.
317
+ detailed = nil
318
+ if msg.kind_of? Exception
319
+ e = msg
320
+ detailed = RightScale::Log.format("Instance stranded", e, :trace)
321
+ msg = e.message
322
+ end
323
+ res = res.content if res.respond_to?(:content)
324
+ msg += ": #{res}" if res
325
+
326
+ @audit.append_error(msg, :category => RightScale::EventCategories::CATEGORY_ERROR) if @audit
327
+ RightScale::Log.error(detailed) if detailed
328
+
329
+ # set stranded state last in case this would prevent final audits from being
330
+ # sent (as it does in testing).
331
+ RightScale::InstanceState.value = 'stranded'
332
+ true
333
+ end
334
+
335
+ # Overrides default shutdown management failure handler in order to strand.
336
+ def handle_failed_shutdown_request(audit, msg, res = nil)
337
+ @audit = audit
338
+ strand(msg, res)
339
+ end
340
+
341
+ # Configure software repositories
342
+ # Note: the configurators may return errors when the platform is not what they expect,
343
+ # for now log error and keep going (to replicate legacy behavior).
344
+ #
345
+ # === Parameters
346
+ # repositories(Array[(RepositoryInstantiation)]):: repositories to be configured
347
+ #
348
+ # === Return
349
+ # true:: Always return true
350
+ def configure_repositories(repositories)
351
+ repositories.each do |repo|
352
+ begin
353
+ klass = repo.name.to_const
354
+ unless klass.nil?
355
+ fz = nil
356
+ if repo.frozen_date
357
+ # gives us date for yesterday since the mirror for today may not have been generated yet
358
+ fz = (Date.parse(repo.frozen_date) - 1).to_s
359
+ fz.gsub!(/-/,"")
360
+ end
361
+ klass.generate("none", repo.base_urls, fz)
362
+ end
363
+ rescue RightScale::Exceptions::PlatformError => e
364
+ # we don't want to use words like error or failed here just because we
365
+ # rely on exceptions for flow-of-control in repo conf generators because
366
+ # that leads to tickets being filed. just say "hey buddy, it didn't work
367
+ # out but it's all okay"
368
+ RightScale::Log.info("Repository configurator #{repo.name} is not suitable for host OS: #{e.message}")
369
+ rescue Exception => e
370
+ RightScale::Log.error("Repository configurator #{repo.name} failed", e)
371
+ end
372
+ end
373
+ if system('which apt-get')
374
+ ENV['DEBIAN_FRONTEND'] = 'noninteractive' # this prevents prompts
375
+ @audit.append_output(`apt-get update 2>&1`)
376
+ elsif system('which yum')
377
+ @audit.append_output(`yum clean metadata`)
378
+ end
379
+ true
380
+ end
381
+
382
+ # Retrieve missing inputs if any
383
+ #
384
+ # === Block
385
+ # Calls given block passing in one argument of type RightScale::OperationResult
386
+ # The argument contains either a failure with associated message or success
387
+ # with the corresponding boot bundle.
388
+ #
389
+ # === Return
390
+ # true:: Always return true
391
+ def prepare_boot_bundle(&cb)
392
+ payload = {:agent_identity => @agent_identity, :audit_id => @audit.audit_id}
393
+ req = RightScale::IdempotentRequest.new('/booter/get_boot_bundle', payload)
394
+
395
+ req.callback do |bundle|
396
+ if bundle.executables.any? { |e| !e.ready }
397
+ retrieve_missing_inputs(bundle) { cb.call(success_result(bundle)) }
398
+ else
399
+ yield success_result(bundle)
400
+ end
401
+ end
402
+
403
+ req.errback do |res|
404
+ yield error_result(RightScale::Log.format('Failed to retrieve boot scripts', res))
405
+ end
406
+
407
+ req.run
408
+ end
409
+
410
+ # Retrieve missing inputs for recipes and RightScripts stored in
411
+ # @recipes and @scripts respectively, update recipe attributes, RightScript
412
+ # parameters and ready fields (set ready field to true if attempt was successful,
413
+ # false otherwise).
414
+ # This is for environment variables that we are waiting on.
415
+ # Retries forever.
416
+ #
417
+ # === Parameters
418
+ # bundle(ExecutableBundle):: bundle containing at least one script/recipe with missing inputs.
419
+ # last_missing_inputs(Hash):: state of missing inputs for refreshing audit message as needed or nil.
420
+ #
421
+ # === Block
422
+ # Continuation block, will be called once attempt to retrieve attributes is completed
423
+ #
424
+ # === Return
425
+ # true:: Always return true
426
+ def retrieve_missing_inputs(bundle, last_missing_inputs = nil, &cb)
427
+ scripts = bundle.executables.select { |e| e.is_a?(RightScale::RightScriptInstantiation) }
428
+ recipes = bundle.executables.select { |e| e.is_a?(RightScale::RecipeInstantiation) }
429
+ scripts_ids = scripts.select { |s| !s.ready }.map { |s| s.id }
430
+ recipes_ids = recipes.select { |r| !r.ready }.map { |r| r.id }
431
+ payload = {:agent_identity => @agent_identity,
432
+ :scripts_ids => scripts_ids,
433
+ :recipes_ids => recipes_ids}
434
+ req = RightScale::IdempotentRequest.new('/booter/get_missing_attributes', payload)
435
+
436
+ req.callback do |res|
437
+ res.each do |e|
438
+ if e.is_a?(RightScale::RightScriptInstantiation)
439
+ if script = scripts.detect { |s| s.id == e.id }
440
+ script.ready = true
441
+ script.parameters = e.parameters
442
+ end
443
+ else
444
+ if recipe = recipes.detect { |s| s.id == e.id }
445
+ recipe.ready = true
446
+ recipe.attributes = e.attributes
447
+ end
448
+ end
449
+ end
450
+ pending_executables = bundle.executables.select { |e| !e.ready }
451
+ if pending_executables.empty?
452
+ yield
453
+ else
454
+ # keep state to provide fewer but more meaningful audits.
455
+ last_missing_inputs ||= {}
456
+ last_missing_inputs[:executables] ||= {}
457
+
458
+ # don't need to audit on each attempt to resolve missing inputs, but nag
459
+ # every so often to let the user know this server is still waiting.
460
+ last_audit_time = last_missing_inputs[:last_audit_time]
461
+ audit_missing_inputs = last_audit_time.nil? || (last_audit_time + MISSING_INPUT_AUDIT_DELAY_SECS < Time.now)
462
+ sent_audit = false
463
+
464
+ # audit missing inputs, if necessary.
465
+ missing_inputs_executables = {}
466
+ pending_executables.each do |e|
467
+ # names of missing inputs are available from RightScripts.
468
+ missing_input_names = []
469
+
470
+ e.input_flags.each {|k,v| missing_input_names << k if v.member?("unready")}
471
+ @audit.append_info("Waiting for the following missing inputs which are used by '#{e.nickname}': #{missing_input_names.join(", ")}")
472
+
473
+ sent_audit = true
474
+ missing_inputs_executables[e.nickname] = missing_input_names
475
+ end
476
+
477
+ # audit any executables which now have all inputs.
478
+ last_missing_inputs[:executables].each_key do |nickname|
479
+ unless missing_inputs_executables[nickname]
480
+ title = RightScale::RightScriptsCookbook.recipe_title(nickname)
481
+ @audit.append_info("The inputs used by #{title} which had been missing have now been resolved.")
482
+ sent_audit = true
483
+ end
484
+ end
485
+ last_missing_inputs[:executables] = missing_inputs_executables
486
+ last_missing_inputs[:last_audit_time] = Time.now if sent_audit
487
+
488
+ # schedule retry to retrieve missing inputs.
489
+ EM.add_timer(MISSING_INPUT_RETRY_DELAY_SECS) { retrieve_missing_inputs(bundle, last_missing_inputs, &cb) }
490
+ end
491
+ end
492
+
493
+ req.errback do |res|
494
+ strand('Failed to retrieve missing inputs', res)
495
+ end
496
+
497
+ req.run
498
+ end
499
+
500
+ # Creates a new sequence for the given context.
501
+ #
502
+ # === Parameters
503
+ # context(RightScale::OperationContext):: context
504
+ #
505
+ # === Return
506
+ # sequence(RightScale::ExecutableSequenceProxy):: new sequence
507
+ def create_sequence(context)
508
+ return RightScale::ExecutableSequenceProxy.new(context)
509
+ end
510
+
511
+ # Retrieve and run boot scripts
512
+ #
513
+ # === Return
514
+ # true:: Always return true
515
+ def run_boot_bundle(bundle)
516
+ @got_boot_bundle = true
517
+
518
+ # Force full converge on boot so that Chef state gets persisted
519
+ context = RightScale::OperationContext.new(bundle, @audit)
520
+ sequence = create_sequence(context)
521
+ sequence.callback do
522
+ if patch = sequence.inputs_patch && !patch.empty?
523
+ payload = {:agent_identity => @agent_identity, :patch => patch}
524
+ send_persistent_push('/updater/update_inputs', payload)
525
+ end
526
+ @audit.update_status("boot completed: #{bundle}")
527
+ yield success_result
528
+ end
529
+ sequence.errback do
530
+ @audit.update_status("boot failed: #{bundle}")
531
+ yield error_result('Failed to run boot bundle')
532
+ end
533
+
534
+ begin
535
+ sequence.run
536
+ rescue Exception => e
537
+ msg = 'Execution of boot sequence failed'
538
+ RightScale::Log.error(msg, e, :trace)
539
+ strand(RightScale::Log.format(msg, e))
540
+ end
541
+
542
+ true
543
+ end
544
+
545
+ # Recovers from an aborted decommission.
546
+ #
547
+ # === Parameters
548
+ # user_id(int):: user id or zero or nil
549
+ # skip_db_update(Boolean):: true to skip db update after shutdown
550
+ # kind(String):: 'reboot', 'stop' or 'terminate'
551
+ #
552
+ # === Return
553
+ # always true
554
+ def recover_decommission(user_id, skip_db_update, kind)
555
+ # skip running decommission bundle again to avoid repeating the failure
556
+ # which caused the previous decommission to kill the agent. log this
557
+ # strange situation and go directly to instance shutdown.
558
+ RightScale::Log.warning("Instance has recovered from an aborted decommission and will perform " +
559
+ "the last requested shutdown: #{kind}")
560
+ RightScale::InstanceState.shutdown(user_id, skip_db_update, kind)
561
+ true
562
+ rescue Exception => e
563
+ RightScale::Log.error("Failed recovering from aborted decommission", e, :trace)
564
+ true
565
+ end
566
+
567
+ end
data/bin/cloud ADDED
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2011 RightScale Inc
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'gem_dependencies'))
23
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'scripts', 'cloud_controller'))
24
+
25
+ RightScale::CloudController.run
data/bin/cook_runner ADDED
@@ -0,0 +1,44 @@
1
+ # === Synopsis:
2
+ # RightScale Chef Cook (cook) - (c) 2010-11 RightScale Inc
3
+ #
4
+ # This utility is meant to be used internally by RightLink, use
5
+ # rs_run_right_script and rs_run_recipe instead.
6
+ #
7
+
8
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'gem_dependencies'))
9
+
10
+ require 'right_agent'
11
+ require 'eventmachine'
12
+ require 'chef'
13
+ require 'fileutils'
14
+ require 'right_scraper'
15
+
16
+ BASE_DIR = File.join(File.dirname(__FILE__), '..')
17
+
18
+ require File.normalize_path(File.join(BASE_DIR, 'lib', 'instance'))
19
+ require File.normalize_path(File.join(BASE_DIR, 'lib', 'instance', 'cook'))
20
+
21
+ # Launch it!
22
+ RightScale::Cook.new.run
23
+
24
+ #
25
+ # Copyright (c) 2009-2011 RightScale Inc
26
+ #
27
+ # Permission is hereby granted, free of charge, to any person obtaining
28
+ # a copy of this software and associated documentation files (the
29
+ # "Software"), to deal in the Software without restriction, including
30
+ # without limitation the rights to use, copy, modify, merge, publish,
31
+ # distribute, sublicense, and/or sell copies of the Software, and to
32
+ # permit persons to whom the Software is furnished to do so, subject to
33
+ # the following conditions:
34
+ #
35
+ # The above copyright notice and this permission notice shall be
36
+ # included in all copies or substantial portions of the Software.
37
+ #
38
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
41
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
42
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
43
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
44
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.